pax_global_header00006660000000000000000000000064145624407250014523gustar00rootroot0000000000000052 comment=68d87db5f26158383ca5c7fe001bc64d1d816471 .codecov.yml000066400000000000000000000000141456244072500133050ustar00rootroot00000000000000comment: no .flake8000066400000000000000000000001671456244072500122460ustar00rootroot00000000000000[flake8] ignore = E203, E266, E501, W503, C901, E741 max-line-length = 88 max-complexity = 18 select = B,C,E,F,W,T4,B9 .gitattributes000066400000000000000000000013751456244072500137700ustar00rootroot00000000000000*.bin filter=lfs diff=lfs merge=lfs -text *.f3grid filter=lfs diff=lfs merge=lfs -text *.fem filter=lfs diff=lfs merge=lfs -text *.inp filter=lfs diff=lfs merge=lfs -text *.med filter=lfs diff=lfs merge=lfs -text *.msh filter=lfs diff=lfs merge=lfs -text *.obj filter=lfs diff=lfs merge=lfs -text *.ply filter=lfs diff=lfs merge=lfs -text *.vtk filter=lfs diff=lfs merge=lfs -text *.vtu filter=lfs diff=lfs merge=lfs -text *.ugrid filter=lfs diff=lfs merge=lfs -text *.mesh filter=lfs diff=lfs merge=lfs -text *.meshb filter=lfs diff=lfs merge=lfs -text *.tec filter=lfs diff=lfs merge=lfs -text *.su2 filter=lfs diff=lfs merge=lfs -text *.ele filter=lfs diff=lfs merge=lfs -text *.node filter=lfs diff=lfs merge=lfs -text *.vol filter=lfs diff=lfs merge=lfs -text .github/000077500000000000000000000000001456244072500124275ustar00rootroot00000000000000.github/ISSUE_TEMPLATE/000077500000000000000000000000001456244072500146125ustar00rootroot00000000000000.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000012171456244072500173050ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: "[BUG]" labels: Needs triage assignees: "" --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** A minimal code example that reproduces the problem would be a big help if you can provide it. Attach a small mesh file if necessary. **Diagnose** I may ask you to cut and paste the output of the following command. ``` pip freeze | grep meshio ``` **Did I help?** If I was able to resolve your problem, consider [sponsoring](https://github.com/sponsors/nschloe) my work on meshio, or [buy me a coffee](https://ko-fi.com/nschloe) to say thanks. .github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000013141456244072500203360ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: "[REQUEST]" labels: Needs triage assignees: '' --- Consider posting in https://github.com/nschloe/meshio/discussions for feedback before raising a feature request. **How would you improve meshio?** Give as much detail as you can. Example code of how you would like it to work would help. **What problem does it solved for you?** What problem do you have that this feature would solve? I may be able to suggest an existing way of solving it. **Did I help** If I was able to resolve your problem, consider [sponsoring](https://github.com/sponsors/nschloe) my work on meshio, or [buy me a coffee](https://ko-fi.com/nschloe) to say thanks. .github/ISSUE_TEMPLATE/new_format.md000066400000000000000000000013751456244072500173030ustar00rootroot00000000000000--- name: New Format about: Suggest support for a new mesh format labels: new format assignees: '' --- Would you like support for a new mesh format in meshio? First check the existing issues, there are a number of format requests already. It's often easy to get rudimentary support for a format, so don't be afraid to start a PR! Consider posting in https://github.com/nschloe/meshio/discussions for feedback before raising a feature request. **Format specification?** Most formats have a detailed specification somewhere online. Make sure to post a link to that. **Did I help** If I was able to resolve your problem, consider [sponsoring](https://github.com/sponsors/nschloe) my work on meshio, or [buy me a coffee](https://ko-fi.com/nschloe) to say thanks. .github/workflows/000077500000000000000000000000001456244072500144645ustar00rootroot00000000000000.github/workflows/ci.yml000066400000000000000000000017251456244072500156070ustar00rootroot00000000000000name: ci on: push: branches: - main pull_request: branches: - main jobs: lint: runs-on: ubuntu-latest steps: - name: Check out repo uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 - name: Run pre-commit uses: pre-commit/action@v3.0.0 build: needs: [lint] runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] python-version: ["3.8", "3.12"] steps: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Checkout code uses: nschloe/action-cached-lfs-checkout@v1 - name: Test with tox run: | pip install tox tox -- --cov meshio --cov-report xml --cov-report term - uses: codecov/codecov-action@v3 if: ${{ matrix.python-version == '3.10' && matrix.os == 'ubuntu-latest' }} .gitignore000066400000000000000000000003051456244072500130550ustar00rootroot00000000000000*.bin *.dat *.dato *.e *.geo *.h5 *.h5m *.msh *.off *.pvtu *.pyc *.xdmf *.xmf *.xml .cache/ MANIFEST README.rst build/ dist/ doc/_build/ *.egg-info/ .pytest_cache/ .coverage .tox/ foo.vtk .vscode/ .pre-commit-config.yaml000066400000000000000000000004541456244072500153530ustar00rootroot00000000000000repos: - repo: https://github.com/PyCQA/isort rev: 5.13.2 hooks: - id: isort - repo: https://github.com/psf/black rev: 24.1.1 hooks: - id: black language_version: python3 - repo: https://github.com/PyCQA/flake8 rev: 7.0.0 hooks: - id: flake8 CHANGELOG.md000066400000000000000000000041101456244072500126740ustar00rootroot00000000000000 # Changelog This document only describes _breaking_ changes in meshio. If you are interested in bug fixes, enhancements etc., best follow [the meshio project on GitHub](https://github.com/nschloe/meshio). ## v5.1.0 (Dec 11, 2021) - CellBlocks are no longer tuples, but classes. You can no longer iterate over them like ```python for cell_type, cell_data in cells: pass ``` Instead, use ```python for cell_block in cells: cell_block.type cell_block.data ``` ## v5.0.0 (Aug 06, 2021) - meshio now only provides one command-line tool, `meshio`, with subcommands like `info`, `convert`, etc. This replaces the former `meshio-info`, `meshio-convert` etc. ## v4.4.0 (Apr 29, 2021) - Polygons are now stored as `"polygon"` cell blocks, not `"polygonN"` (where `N` is the number of nodes per polygon). One can simply retrieve the number of points via `cellblock.data.shape[1]`. ## v4.0.0 (Feb 18, 2020) - `mesh.cells` used to be a dictionary of the form ```python { "triangle": [[0, 1, 2], [0, 2, 3]], "quad": [[0, 7, 1, 10], ...] } ``` From 4.0.0 on, `mesh.cells` is a list of tuples, ```python [ ("triangle", [[0, 1, 2], [0, 2, 3]]), ("quad", [[0, 7, 1, 10], ...]) ] ``` This has the advantage that multiple blocks of the same cell type can be accounted for. Also, cell ordering can be preserved. You can now use the method `mesh.get_cells_type("triangle")` to get all cells of `"triangle"` type, or use `mesh.cells_dict` to build the old dictionary structure. - `mesh.cell_data` used to be a dictionary of the form ```python { "triangle": {"a": [0.5, 1.3], "b": [2.17, 41.3]}, "quad": {"a": [1.1, -0.3, ...], "b": [3.14, 1.61, ...]}, } ``` From 4.0.0 on, `mesh.cell_data` is a dictionary of lists, ```python { "a": [[0.5, 1.3], [1.1, -0.3, ...]], "b": [[2.17, 41.3], [3.14, 1.61, ...]], } ``` Each data list, e.g., `mesh.cell_data["a"]`, can be `zip`ped with `mesh.cells`. An old-style `cell_data` dictionary can be retrieved via `mesh.cell_data_dict`. CITATION.cff000066400000000000000000000004631456244072500127640ustar00rootroot00000000000000cff-version: 1.2.0 message: "If you use this software, please cite it as below." authors: - family-names: "Schlömer" given-names: "Nico" orcid: "https://orcid.org/0000-0001-5228-0946" title: "meshio: Tools for mesh files" doi: 10.5281/zenodo.1173115 url: https://github.com/nschloe/meshio license: MIT CODE_OF_CONDUCT.md000066400000000000000000000064411456244072500136730ustar00rootroot00000000000000# meshio Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct/ [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq/ CONTRIBUTING.md000066400000000000000000000014331456244072500133210ustar00rootroot00000000000000# meshio contributing guidelines The meshio community appreciates your contributions via issues and pull requests. Note that the [code of conduct](CODE_OF_CONDUCT.md) applies to all interactions with the meshio project, including issues and pull requests. When submitting pull requests, please follow the style guidelines of the project, ensure that your code is tested and documented, and write good commit messages, e.g., following [these guidelines](https://chris.beams.io/posts/git-commit/). By submitting a pull request, you are licensing your code under the project [license](LICENSE.txt) and affirming that you either own copyright (automatic for most individuals) or are authorized to distribute under the project license (e.g., in case your employer retains copyright on your work). LICENSE.txt000066400000000000000000000021051456244072500127100ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015-2021 Nico Schlömer et al. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. MANIFEST.in000066400000000000000000000003241456244072500126240ustar00rootroot00000000000000include LICENSE.txt # Don't recursively include everything that's in test; there may be cruft files, # left-overs from experiments etc. include tests/*.py # include tests/meshes/ recursive-include tests/meshes * README.md000066400000000000000000000216341456244072500123540ustar00rootroot00000000000000

meshio

I/O for mesh files.

[![PyPi Version](https://img.shields.io/pypi/v/meshio.svg?style=flat-square)](https://pypi.org/project/meshio/) [![Anaconda Cloud](https://anaconda.org/conda-forge/meshio/badges/version.svg?=style=flat-square)](https://anaconda.org/conda-forge/meshio/) [![Packaging status](https://repology.org/badge/tiny-repos/python:meshio.svg)](https://repology.org/project/python:meshio/versions) [![PyPI pyversions](https://img.shields.io/pypi/pyversions/meshio.svg?style=flat-square)](https://pypi.org/project/meshio/) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1173115.svg?style=flat-square)](https://doi.org/10.5281/zenodo.1173115) [![GitHub stars](https://img.shields.io/github/stars/nschloe/meshio.svg?style=flat-square&logo=github&label=Stars&logoColor=white)](https://github.com/nschloe/meshio) [![Downloads](https://pepy.tech/badge/meshio/month?style=flat-square)](https://pepy.tech/project/meshio) [![Discord](https://img.shields.io/static/v1?logo=discord&logoColor=white&label=chat&message=on%20discord&color=7289da&style=flat-square)](https://discord.gg/Z6DMsJh4Hr) [![gh-actions](https://img.shields.io/github/workflow/status/nschloe/meshio/ci?style=flat-square)](https://github.com/nschloe/meshio/actions?query=workflow%3Aci) [![codecov](https://img.shields.io/codecov/c/github/nschloe/meshio.svg?style=flat-square)](https://app.codecov.io/gh/nschloe/meshio) [![LGTM](https://img.shields.io/lgtm/grade/python/github/nschloe/meshio.svg?style=flat-square)](https://lgtm.com/projects/g/nschloe/meshio) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg?style=flat-square)](https://github.com/psf/black) There are various mesh formats available for representing unstructured meshes. meshio can read and write all of the following and smoothly converts between them: > [Abaqus](http://abaqus.software.polimi.it/v6.14/index.html) (`.inp`), > ANSYS msh (`.msh`), > [AVS-UCD](https://lanl.github.io/LaGriT/pages/docs/read_avs.html) (`.avs`), > [CGNS](https://cgns.github.io/) (`.cgns`), > [DOLFIN XML](https://manpages.ubuntu.com/manpages/jammy/en/man1/dolfin-convert.1.html) (`.xml`), > [Exodus](https://nschloe.github.io/meshio/exodus.pdf) (`.e`, `.exo`), > [FLAC3D](https://www.itascacg.com/software/flac3d) (`.f3grid`), > [H5M](https://www.mcs.anl.gov/~fathom/moab-docs/h5mmain.html) (`.h5m`), > [Kratos/MDPA](https://github.com/KratosMultiphysics/Kratos/wiki/Input-data) (`.mdpa`), > [Medit](https://people.sc.fsu.edu/~jburkardt/data/medit/medit.html) (`.mesh`, `.meshb`), > [MED/Salome](https://docs.salome-platform.org/latest/dev/MEDCoupling/developer/med-file.html) (`.med`), > [Nastran](https://help.autodesk.com/view/NSTRN/2019/ENU/?guid=GUID-42B54ACB-FBE3-47CA-B8FE-475E7AD91A00) (bulk data, `.bdf`, `.fem`, `.nas`), > [Netgen](https://github.com/ngsolve/netgen) (`.vol`, `.vol.gz`), > [Neuroglancer precomputed format](https://github.com/google/neuroglancer/tree/master/src/neuroglancer/datasource/precomputed#mesh-representation-of-segmented-object-surfaces), > [Gmsh](https://gmsh.info/doc/texinfo/gmsh.html#File-formats) (format versions 2.2, 4.0, and 4.1, `.msh`), > [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file) (`.obj`), > [OFF](https://segeval.cs.princeton.edu/public/off_format.html) (`.off`), > [PERMAS](https://www.intes.de) (`.post`, `.post.gz`, `.dato`, `.dato.gz`), > [PLY]() (`.ply`), > [STL]() (`.stl`), > [Tecplot .dat](http://paulbourke.net/dataformats/tp/), > [TetGen .node/.ele](https://wias-berlin.de/software/tetgen/fformats.html), > [SVG](https://www.w3.org/TR/SVG/) (2D output only) (`.svg`), > [SU2](https://su2code.github.io/docs_v7/Mesh-File/) (`.su2`), > [UGRID](https://www.simcenter.msstate.edu/software/documentation/ug_io/3d_grid_file_type_ugrid.html) (`.ugrid`), > [VTK](https://vtk.org/wp-content/uploads/2015/04/file-formats.pdf) (`.vtk`), > [VTU](https://vtk.org/Wiki/VTK_XML_Formats) (`.vtu`), > [WKT](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry) ([TIN](https://en.wikipedia.org/wiki/Triangulated_irregular_network)) (`.wkt`), > [XDMF](https://xdmf.org/index.php/XDMF_Model_and_Format) (`.xdmf`, `.xmf`). ([Here's a little survey](https://forms.gle/PSeNb3N3gv3wbEus8) on which formats are actually used.) Install with one of ``` pip install meshio[all] conda install -c conda-forge meshio ``` (`[all]` pulls in all optional dependencies. By default, meshio only uses numpy.) You can then use the command-line tool ```sh meshio convert input.msh output.vtk # convert between two formats meshio info input.xdmf # show some info about the mesh meshio compress input.vtu # compress the mesh file meshio decompress input.vtu # decompress the mesh file meshio binary input.msh # convert to binary format meshio ascii input.msh # convert to ASCII format ``` with any of the supported formats. In Python, simply do ```python import meshio mesh = meshio.read( filename, # string, os.PathLike, or a buffer/open file # file_format="stl", # optional if filename is a path; inferred from extension # see meshio-convert -h for all possible formats ) # mesh.points, mesh.cells, mesh.cells_dict, ... # mesh.vtk.read() is also possible ``` to read a mesh. To write, do ```python import meshio # two triangles and one quad points = [ [0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0], [2.0, 0.0], [2.0, 1.0], ] cells = [ ("triangle", [[0, 1, 2], [1, 3, 2]]), ("quad", [[1, 4, 5, 3]]), ] mesh = meshio.Mesh( points, cells, # Optionally provide extra data on points, cells, etc. point_data={"T": [0.3, -1.2, 0.5, 0.7, 0.0, -3.0]}, # Each item in cell data must match the cells array cell_data={"a": [[0.1, 0.2], [0.4]]}, ) mesh.write( "foo.vtk", # str, os.PathLike, or buffer/open file # file_format="vtk", # optional if first argument is a path; inferred from extension ) # Alternative with the same options meshio.write_points_cells("foo.vtk", points, cells) ``` For both input and output, you can optionally specify the exact `file_format` (in case you would like to enforce ASCII over binary VTK, for example). #### Time series The [XDMF format](https://xdmf.org/index.php/XDMF_Model_and_Format) supports time series with a shared mesh. You can write times series data using meshio with ```python with meshio.xdmf.TimeSeriesWriter(filename) as writer: writer.write_points_cells(points, cells) for t in [0.0, 0.1, 0.21]: writer.write_data(t, point_data={"phi": data}) ``` and read it with ```python with meshio.xdmf.TimeSeriesReader(filename) as reader: points, cells = reader.read_points_cells() for k in range(reader.num_steps): t, point_data, cell_data = reader.read_data(k) ``` ### ParaView plugin gmsh paraview *A Gmsh file opened with ParaView.* If you have downloaded a binary version of ParaView, you may proceed as follows. - Install meshio for the Python major version that ParaView uses (check `pvpython --version`) - Open ParaView - Find the file `paraview-meshio-plugin.py` of your meshio installation (on Linux: `~/.local/share/paraview-5.9/plugins/`) and load it under _Tools / Manage Plugins / Load New_ - _Optional:_ Activate _Auto Load_ You can now open all meshio-supported files in ParaView. ### Performance comparison The comparisons here are for a triangular mesh with about 900k points and 1.8M triangles. The red lines mark the size of the mesh in memory. #### File sizes file size #### I/O speed performance #### Maximum memory usage memory usage ### Installation meshio is [available from the Python Package Index](https://pypi.org/project/meshio/), so simply run ``` pip install meshio ``` to install. Additional dependencies (`netcdf4`, `h5py`) are required for some of the output formats and can be pulled in by ``` pip install meshio[all] ``` You can also install meshio from [Anaconda](https://anaconda.org/conda-forge/meshio): ``` conda install -c conda-forge meshio ``` ### Testing To run the meshio unit tests, check out this repository and type ``` tox ``` ### License meshio is published under the [MIT license](https://en.wikipedia.org/wiki/MIT_License). doc/000077500000000000000000000000001456244072500116345ustar00rootroot00000000000000doc/cell_types.tex000066400000000000000000000277761456244072500145440ustar00rootroot00000000000000\documentclass[convert=pdf2svg]{standalone} % \documentclass{article} \usepackage[T1]{fontenc} \usepackage{lmodern} \renewcommand{\familydefault}{\sfdefault} \usepackage{tikz} \usepackage{tikz-3dplot} \usetikzlibrary{external} \tikzset{external/force remake} \tikzset{external/disable dependency files} \tikzset{external/aux in dpth={false}} % uncomment this to generate a figure for each cell type (and change documentclass to article) % \tikzexternalize \tikzstyle{vertex} = [circle,draw=black,fill=black,scale = 0.5] \tdplotsetmaincoords{70}{110} % cnode(tag,x,y,z,label,label_pos) \def\cnode(#1,#2,#3,#4,#5,#6){ \node (#1) at (#2,#3,#4) [vertex,label=#6:$\mathsf{#5}$] {}; } \pagestyle{empty} \begin{document} \begin{tabular}{ccc} vertex & line & line3 \\ \tikzsetnextfilename{vertex} \begin{tikzpicture}[scale = 2] % \useasboundingbox (-2.5,-2.5) (2.5,2.5); \cnode(n0,0,0,0,0,below right); \end{tikzpicture} & \tikzsetnextfilename{line} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \draw (n0) -- (n1); \end{tikzpicture} & \tikzsetnextfilename{line3} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,1,0,0,2,below right); \draw (n0) -- (n2) -- (n1); \end{tikzpicture} \\[1 em] triangle & triangle6 & triangle7 \\ \tikzsetnextfilename{triangle} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,0,2,0,2,right); \draw (n0) -- (n1) -- (n2) -- (n0); \end{tikzpicture} & \tikzsetnextfilename{triangle6} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,0,2,0,2,right); \cnode(n3,1,0,0,3,below right); \cnode(n4,1,1,0,4,right); \cnode(n5,0,1,0,5,below right); \draw (n0) -- (n3) -- (n1) -- (n4) -- (n2) -- (n5) -- (n0); \end{tikzpicture} & \tikzsetnextfilename{triangle7} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,0,2,0,2,right); \cnode(n3,1,0,0,3,below right); \cnode(n4,1,1,0,4,right); \cnode(n5,0,1,0,5,below right); \cnode(n6,0.5,0.5,0,6,below right); \draw (n0) -- (n3) -- (n1) -- (n4) -- (n2) -- (n5) -- (n0); \end{tikzpicture} \\[1 em] quad & quad8 & quad9 \\ \tikzsetnextfilename{quad} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,2,2,0,2,below right); \cnode(n3,0,2,0,3,below right); \draw (n0) -- (n1) -- (n2) -- (n3) -- (n0); \end{tikzpicture} & \tikzsetnextfilename{quad8} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,2,2,0,2,below right); \cnode(n3,0,2,0,3,below right); \cnode(n4,1,0,0,4,below right); \cnode(n5,2,1,0,5,below right); \cnode(n6,1,2,0,6,below right); \cnode(n7,0,1,0,7,below right); \draw (n0) -- (n4) -- (n1) -- (n5) -- (n2) -- (n6) -- (n3) -- (n7) -- (n0); \end{tikzpicture} & \tikzsetnextfilename{quad9} \begin{tikzpicture}[scale = 2] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,2,2,0,2,below right); \cnode(n3,0,2,0,3,below right); \cnode(n4,1,0,0,4,below right); \cnode(n5,2,1,0,5,below right); \cnode(n6,1,2,0,6,below right); \cnode(n7,0,1,0,7,below right); \cnode(n8,1,1,0,8,below right); \draw (n0) -- (n4) -- (n1) -- (n5) -- (n2) -- (n6) -- (n3) -- (n7) -- (n0); \end{tikzpicture} \\[1 em] tetra & tetra10 & hexahedron \\ \tikzsetnextfilename{tetra} \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,0,2,0,2,below right); \cnode(n3,0,0,2,3,right); \draw (n0) -- (n1) -- (n2) -- (n0); \draw (n0) -- (n3); \draw (n1) -- (n3); \draw (n2) -- (n3); \end{tikzpicture} & \tikzsetnextfilename{tetra10} % VTK \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,0,2,0,2,below right); \cnode(n3,0,0,2,3,right); \cnode(n4,1,0,0,4,below right); \cnode(n5,1,1,0,5,below right); \cnode(n6,0,1,0,6,below right); \cnode(n7,0,0,1,7,below right); \cnode(n8,1,0,1,8,below right); \cnode(n9,0,1,1,9,right); \draw (n0) -- (n4) -- (n1) -- (n5) -- (n2) -- (n6) -- (n0); \draw (n0) -- (n7) -- (n3); \draw (n1) -- (n8) -- (n3); \draw (n2) -- (n9) -- (n3); \end{tikzpicture} & \tikzsetnextfilename{hexahedron} \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,2,2,0,2,below right); \cnode(n3,0,2,0,3,below right); \cnode(n4,0,0,2,4,below right); \cnode(n5,2,0,2,5,below right); \cnode(n6,2,2,2,6,below right); \cnode(n7,0,2,2,7,below right); \draw (n0) -- (n1) -- (n2) -- (n3) -- (n0); \draw (n4) -- (n5) -- (n6) -- (n7) -- (n4); \draw (n0) -- (n4); \draw (n1) -- (n5); \draw (n2) -- (n6); \draw (n3) -- (n7); \end{tikzpicture} \\[1 em] hexahedron20 & hexahedron24 & hexahedron27 \\ \tikzsetnextfilename{hexahedron20} % VTK != gmsh \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,2,2,0,2,below right); \cnode(n3,0,2,0,3,below right); \cnode(n4,0,0,2,4,below right); \cnode(n5,2,0,2,5,below right); \cnode(n6,2,2,2,6,below right); \cnode(n7,0,2,2,7,below right); \cnode(n8,1,0,0,8,below right); \cnode(n9,2,1,0,9,below right); \cnode(n10,1,2,0,10,below right); \cnode(n11,0,1,0,11,below right); \cnode(n12,1,0,2,12,below right); \cnode(n13,2,1,2,13,below right); \cnode(n14,1,2,2,14,below right); \cnode(n15,0,1,2,15,below right); \cnode(n16,0,0,1,16,below right); \cnode(n17,2,0,1,17,below right); \cnode(n18,2,2,1,18,below right); \cnode(n19,0,2,1,19,below right); \draw (n0) -- (n8) -- (n1) -- (n9) -- (n2) -- (n10) -- (n3) -- (n11) -- (n0); \draw (n4) -- (n12) -- (n5) -- (n13) -- (n6) -- (n14) -- (n7) -- (n15) -- (n4); \draw (n0) -- (n16) -- (n4); \draw (n1) -- (n17) -- (n5); \draw (n2) -- (n18) -- (n6); \draw (n3) -- (n19) -- (n7); \end{tikzpicture} & \tikzsetnextfilename{hexahedron24} % VTK \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,2,2,0,2,below right); \cnode(n3,0,2,0,3,below right); \cnode(n4,0,0,2,4,below right); \cnode(n5,2,0,2,5,below right); \cnode(n6,2,2,2,6,below right); \cnode(n7,0,2,2,7,below right); \cnode(n8,1,0,0,8,below right); \cnode(n9,2,1,0,9,below right); \cnode(n10,1,2,0,10,below right); \cnode(n11,0,1,0,11,below right); \cnode(n12,1,0,2,12,below right); \cnode(n13,2,1,2,13,below right); \cnode(n14,1,2,2,14,below right); \cnode(n15,0,1,2,15,below right); \cnode(n16,0,0,1,16,below right); \cnode(n17,2,0,1,17,below right); \cnode(n18,2,2,1,18,below right); \cnode(n19,0,2,1,19,below right); \cnode(n20,0,1,1,20,below right); \cnode(n21,2,1,1,21,below right); \cnode(n22,1,0,1,22,below right); \cnode(n23,1,2,1,23,below right); \draw (n0) -- (n8) -- (n1) -- (n9) -- (n2) -- (n10) -- (n3) -- (n11) -- (n0); \draw (n4) -- (n12) -- (n5) -- (n13) -- (n6) -- (n14) -- (n7) -- (n15) -- (n4); \draw (n0) -- (n16) -- (n4); \draw (n1) -- (n17) -- (n5); \draw (n2) -- (n18) -- (n6); \draw (n3) -- (n19) -- (n7); \end{tikzpicture} & \tikzsetnextfilename{hexahedron27} % VTK != gmsh \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,2,2,0,2,below right); \cnode(n3,0,2,0,3,below right); \cnode(n4,0,0,2,4,below right); \cnode(n5,2,0,2,5,below right); \cnode(n6,2,2,2,6,below right); \cnode(n7,0,2,2,7,below right); \cnode(n8,1,0,0,8,below right); \cnode(n9,2,1,0,9,below right); \cnode(n10,1,2,0,10,below right); \cnode(n11,0,1,0,11,below right); \cnode(n12,1,0,2,12,below right); \cnode(n13,2,1,2,13,below right); \cnode(n14,1,2,2,14,below right); \cnode(n15,0,1,2,15,below right); \cnode(n16,0,0,1,16,below right); \cnode(n17,2,0,1,17,below right); \cnode(n18,2,2,1,18,below right); \cnode(n19,0,2,1,19,below right); \cnode(n20,0,1,1,20,below right); \cnode(n21,2,1,1,21,below right); \cnode(n22,1,0,1,22,below right); \cnode(n23,1,2,1,23,below right); \cnode(n24,1,1,0,24,below right); \cnode(n25,1,1,2,25,below right); \cnode(n26,1,1,1,26,below right); \draw (n0) -- (n8) -- (n1) -- (n9) -- (n2) -- (n10) -- (n3) -- (n11) -- (n0); \draw (n4) -- (n12) -- (n5) -- (n13) -- (n6) -- (n14) -- (n7) -- (n15) -- (n4); \draw (n0) -- (n16) -- (n4); \draw (n1) -- (n17) -- (n5); \draw (n2) -- (n18) -- (n6); \draw (n3) -- (n19) -- (n7); \end{tikzpicture} \\[1 em] wedge & wedge12 & wedge15 \\ \tikzsetnextfilename{wedge} % gmsh != VTK \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,0,2,0,2,below right); \cnode(n3,0,0,2,3,below right); \cnode(n4,2,0,2,4,below right); \cnode(n5,0,2,2,5,below right); \draw (n0) -- (n1) -- (n2) -- (n0); \draw (n3) -- (n4) -- (n5) -- (n3); \draw (n0) -- (n3); \draw (n1) -- (n4); \draw (n2) -- (n5); \end{tikzpicture} & \tikzsetnextfilename{wedge12} % VTK \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,0,2,0,2,below right); \cnode(n3,0,0,2,3,below right); \cnode(n4,2,0,2,4,below right); \cnode(n5,0,2,2,5,below right); \cnode(n6,1,0,0,6,below right); \cnode(n7,1,1,0,7,below right); \cnode(n8,0,1,0,8,below right); \cnode(n9,1,0,2,9,below right); \cnode(n10,1,1,2,10,below right); \cnode(n11,0,1,2,11,below right); \draw (n0) -- (n6) -- (n1) -- (n7) -- (n2) -- (n8) -- (n0); \draw (n3) -- (n9) -- (n4) -- (n10) -- (n5) -- (n11) -- (n3); \draw (n0) -- (n3); \draw (n1) -- (n4); \draw (n2) -- (n5); \end{tikzpicture} & \tikzsetnextfilename{wedge15} % VTK != gmsh \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,0,2,0,2,below right); \cnode(n3,0,0,2,3,below right); \cnode(n4,2,0,2,4,below right); \cnode(n5,0,2,2,5,below right); \cnode(n6,1,0,0,6,below right); \cnode(n7,1,1,0,7,below right); \cnode(n8,0,1,0,8,below right); \cnode(n9,1,0,2,9,below right); \cnode(n10,1,1,2,10,below right); \cnode(n11,0,1,2,11,below right); \cnode(n12,0,0,1,12,below right); \cnode(n13,2,0,1,13,below right); \cnode(n14,0,2,1,14,below right); \draw (n0) -- (n6) -- (n1) -- (n7) -- (n2) -- (n8) -- (n0); \draw (n3) -- (n9) -- (n4) -- (n10) -- (n5) -- (n11) -- (n3); \draw (n0) -- (n12) -- (n3); \draw (n1) -- (n13) -- (n4); \draw (n2) -- (n14) -- (n5); \end{tikzpicture} \\[1 em] pyramid & pyramid13 & pyramid14 \\ \tikzsetnextfilename{pyramid} \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,2,2,0,2,below right); \cnode(n3,0,2,0,3,below right); \cnode(n4,1,1,2,4,right); \draw (n0) -- (n1) -- (n2) -- (n3) -- (n0); \draw (n0) -- (n4); \draw (n1) -- (n4); \draw (n2) -- (n4); \draw (n3) -- (n4); \end{tikzpicture} & \tikzsetnextfilename{pyramid13} % VTK != gmsh \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,2,2,0,2,below right); \cnode(n3,0,2,0,3,below right); \cnode(n4,1,1,2,4,right); \cnode(n5,1,0,0,5,below right); \cnode(n6,2,1,0,6,below right); \cnode(n7,1,2,0,7,below right); \cnode(n8,0,1,0,8,below right); \cnode(n9,0.5,0.5,1,9,below right); \cnode(n10,1.5,0.5,1,10,below right); \cnode(n11,1.5,1.5,1,11,below right); \cnode(n12,0.5,1.5,1,12,right); \draw (n0) -- (n5) -- (n1) -- (n6) -- (n2) -- (n7) -- (n3) -- (n8) -- (n0); \draw (n0) -- (n9) -- (n4); \draw (n1) -- (n10) -- (n4); \draw (n2) -- (n11) -- (n4); \draw (n3) -- (n12) -- (n4); \end{tikzpicture} & \tikzsetnextfilename{pyramid14} % gmsh \begin{tikzpicture}[scale = 2, tdplot_main_coords] \cnode(n0,0,0,0,0,below right); \cnode(n1,2,0,0,1,below right); \cnode(n2,2,2,0,2,below right); \cnode(n3,0,2,0,3,below right); \cnode(n4,1,1,2,4,right); \cnode(n5,1,0,0,5,below right); \cnode(n6,2,1,0,8,below right); \cnode(n7,1,2,0,10,below right); \cnode(n8,0,1,0,6,below right); \cnode(n9,0.5,0.5,1,7,below right); \cnode(n10,1.5,0.5,1,9,below right); \cnode(n11,1.5,1.5,1,11,below right); \cnode(n12,0.5,1.5,1,12,right); \cnode(n13,1,1,0,13,below right); \draw (n0) -- (n5) -- (n1) -- (n6) -- (n2) -- (n7) -- (n3) -- (n8) -- (n0); \draw (n0) -- (n9) -- (n4); \draw (n1) -- (n10) -- (n4); \draw (n2) -- (n11) -- (n4); \draw (n3) -- (n12) -- (n4); \end{tikzpicture} \end{tabular} \end{document} justfile000066400000000000000000000014261456244072500126420ustar00rootroot00000000000000version := `python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])"` default: @echo "\"just publish\"?" tag: @if [ "$(git rev-parse --abbrev-ref HEAD)" != "main" ]; then exit 1; fi curl -H "Authorization: token `cat ~/.github-access-token`" -d '{"tag_name": "v{{version}}"}' https://api.github.com/repos/nschloe/meshio/releases upload: clean @if [ "$(git rev-parse --abbrev-ref HEAD)" != "main" ]; then exit 1; fi # https://stackoverflow.com/a/58756491/353337 python3 -m build --sdist --wheel . twine upload dist/* publish: tag upload clean: @find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf @rm -rf src/*.egg-info/ build/ dist/ .tox/ format: isort . black . blacken-docs README.md lint: black --check . flake8 . logo/000077500000000000000000000000001456244072500120275ustar00rootroot00000000000000logo/logo.py000066400000000000000000000051611456244072500133440ustar00rootroot00000000000000import numpy as np import optimesh import pygmsh import meshio # def _old_logo() # with pygmsh.occ.Geometry() as geom: # characteristic_length_min = 0.5 # characteristic_length_max = 0.5 # # container = geom.add_rectangle([0.0, 0.0, 0.0], 10.0, 10.0) # # letter_i = geom.add_rectangle([2.0, 2.0, 0.0], 1.0, 4.5) # i_dot = geom.add_disk([2.5, 7.5, 0.0], 0.6) # # disk1 = geom.add_disk([6.25, 4.5, 0.0], 2.5) # disk2 = geom.add_disk([6.25, 4.5, 0.0], 1.5) # letter_o = geom.boolean_difference([disk1], [disk2]) # # geom.boolean_difference([container], [letter_i, i_dot, letter_o]) # # mesh = pygmsh.generate_mesh(geom) # # X, cells = mesh.points, mesh.cells # X, cells = optimesh.cvt.lloyd.quasi_newton_uniform_lloyd( # X, cells["triangle"], 1.0e-3, 1000 # ) # return X, cells def create_logo2(y=0.0): with pygmsh.geo.Geometry() as geom: mesh_size = 0.15 arrow1 = geom.add_polygon( [ [0.10, 0.70 - y, 0.0], [0.35, 0.60 - y, 0.0], [0.35, 0.65 - y, 0.0], [0.80, 0.65 - y, 0.0], [0.80, 0.75 - y, 0.0], [0.35, 0.75 - y, 0.0], [0.35, 0.80 - y, 0.0], ], mesh_size=mesh_size, make_surface=False, ) arrow2 = geom.add_polygon( [ [0.90, 0.30 + y, 0.0], [0.65, 0.40 + y, 0.0], [0.65, 0.35 + y, 0.0], [0.20, 0.35 + y, 0.0], [0.20, 0.25 + y, 0.0], [0.65, 0.25 + y, 0.0], [0.65, 0.20 + y, 0.0], ], mesh_size=mesh_size, make_surface=False, ) geom.add_polygon( [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]], mesh_size=mesh_size, holes=[arrow1, arrow2], ) mesh = geom.generate_mesh() # return mesh.points, mesh.cells["triangle"] X = mesh.points cells = mesh.get_cells_type("triangle") # np.bincount doesn't work with uint # cells = cells.astype(int) X, cells = optimesh.cvt.quasi_newton_uniform_full( X, cells, 1.0e-10, 100, verbose=True ) return X, cells if __name__ == "__main__": X, cells = create_logo2(y=0.08) mesh = meshio.Mesh(X, {"triangle": cells}) meshio.svg.write("logo.svg", mesh, image_width=300) X = np.column_stack([X, np.zeros_like(X[:, 0])]) meshio.Mesh(X, {"triangle": cells}).write("logo.vtk") pyproject.toml000066400000000000000000000030541456244072500140050ustar00rootroot00000000000000[build-system] requires = ["setuptools>=42", "wheel"] build-backend = "setuptools.build_meta" [project] name = "meshio" version = "5.3.5" description = "I/O for many mesh formats" readme = "README.md" requires-python = ">=3.8" license = {file = "LICENSE.txt"} keywords = [ "mesh", "file formats", "scientific", "engineering", "fem", "finite elements" ] authors = [ {email = "nico.schloemer@gmail.com"}, {name = "Nico Schlömer"} ] classifiers = [ "Development Status :: 5 - Production/Stable", "Programming Language :: Python", "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Scientific/Engineering", "Topic :: Utilities", ] dependencies = [ "importlib_metadata; python_version<'3.8'", "numpy>=1.20.0", "rich", ] [project.optional-dependencies] all = [ "netCDF4", "h5py" # CGNS, H5M, MED, XDMF formats ] [project.urls] homepage = "https://github.com/nschloe/meshio" code = "https://github.com/nschloe/meshio" issues = "https://github.com/nschloe/meshio/issues" [project.entry-points.console_scripts] meshio = "meshio._cli:main" [tool.isort] profile = "black" # [options.data_files] # share/paraview-5.9/plugins = # tools/paraview-meshio-plugin.py src/000077500000000000000000000000001456244072500116565ustar00rootroot00000000000000src/meshio/000077500000000000000000000000001456244072500131425ustar00rootroot00000000000000src/meshio/__about__.py000066400000000000000000000004361456244072500154250ustar00rootroot00000000000000try: # Python 3.8+ from importlib import metadata except ImportError: try: import importlib_metadata as metadata except ImportError: __version__ = "unknown" try: __version__ = metadata.version("meshio") except Exception: __version__ = "unknown" src/meshio/__init__.py000066400000000000000000000023521456244072500152550ustar00rootroot00000000000000from . import ( _cli, abaqus, ansys, avsucd, cgns, dolfin, exodus, flac3d, gmsh, h5m, hmf, mdpa, med, medit, nastran, netgen, neuroglancer, obj, off, permas, ply, stl, su2, svg, tecplot, tetgen, ugrid, vtk, vtu, wkt, xdmf, ) from .__about__ import __version__ from ._exceptions import ReadError, WriteError from ._helpers import ( deregister_format, extension_to_filetypes, read, register_format, write, write_points_cells, ) from ._mesh import CellBlock, Mesh __all__ = [ "abaqus", "ansys", "avsucd", "cgns", "dolfin", "exodus", "flac3d", "gmsh", "h5m", "hmf", "mdpa", "med", "medit", "nastran", "netgen", "neuroglancer", "obj", "off", "permas", "ply", "stl", "su2", "svg", "tecplot", "tetgen", "ugrid", "vtk", "vtu", "wkt", "xdmf", "_cli", "read", "write", "register_format", "deregister_format", "write_points_cells", "extension_to_filetypes", "Mesh", "CellBlock", "ReadError", "WriteError", "topological_dimension", "__version__", ] src/meshio/_cli/000077500000000000000000000000001456244072500140505ustar00rootroot00000000000000src/meshio/_cli/__init__.py000066400000000000000000000000541456244072500161600ustar00rootroot00000000000000from ._main import main __all__ = ["main"] src/meshio/_cli/_ascii.py000066400000000000000000000035151456244072500156550ustar00rootroot00000000000000import os import pathlib from .. import ansys, flac3d, gmsh, mdpa, ply, stl, vtk, vtu, xdmf from .._common import error from .._helpers import _filetypes_from_path, read, reader_map def add_args(parser): parser.add_argument("infile", type=str, help="mesh file to convert") parser.add_argument( "--input-format", "-i", type=str, choices=sorted(list(reader_map.keys())), help="input file format", default=None, ) def ascii(args): if args.input_format: fmts = [args.input_format] else: fmts = _filetypes_from_path(pathlib.Path(args.infile)) # pick the first fmt = fmts[0] size = os.stat(args.infile).st_size print(f"File size before: {size / 1024 ** 2:.2f} MB") mesh = read(args.infile, file_format=args.input_format) # # Some converters (like VTK) require `points` to be contiguous. # mesh.points = np.ascontiguousarray(mesh.points) # write it out if fmt == "ansys": ansys.write(args.infile, mesh, binary=False) elif fmt == "flac3d": flac3d.write(args.infile, mesh, binary=False) elif fmt == "gmsh": gmsh.write(args.infile, mesh, binary=False) elif fmt == "mdpa": mdpa.write(args.infile, mesh, binary=False) elif fmt == "ply": ply.write(args.infile, mesh, binary=False) elif fmt == "stl": stl.write(args.infile, mesh, binary=False) elif fmt == "vtk": vtk.write(args.infile, mesh, binary=False) elif fmt == "vtu": vtu.write(args.infile, mesh, binary=False) elif fmt == "xdmf": xdmf.write(args.infile, mesh, data_format="XML") else: error(f"Don't know how to convert {args.infile} to ASCII format.") return 1 size = os.stat(args.infile).st_size print(f"File size after: {size / 1024 ** 2:.2f} MB") return 0 src/meshio/_cli/_binary.py000066400000000000000000000034351456244072500160520ustar00rootroot00000000000000import os import pathlib from .. import ansys, flac3d, gmsh, mdpa, ply, stl, vtk, vtu, xdmf from .._helpers import _filetypes_from_path, read, reader_map def add_args(parser): parser.add_argument("infile", type=str, help="mesh file to convert") parser.add_argument( "--input-format", "-i", type=str, choices=sorted(list(reader_map.keys())), help="input file format", default=None, ) def binary(args): if args.input_format: fmts = [args.input_format] else: fmts = _filetypes_from_path(pathlib.Path(args.infile)) # pick the first fmt = fmts[0] size = os.stat(args.infile).st_size print(f"File size before: {size / 1024 ** 2:.2f} MB") mesh = read(args.infile, file_format=args.input_format) # # Some converters (like VTK) require `points` to be contiguous. # mesh.points = np.ascontiguousarray(mesh.points) # write it out if fmt == "ansys": ansys.write(args.infile, mesh, binary=True) elif fmt == "flac3d": flac3d.write(args.infile, mesh, binary=True) elif fmt == "gmsh": gmsh.write(args.infile, mesh, binary=True) elif fmt == "mdpa": mdpa.write(args.infile, mesh, binary=True) elif fmt == "ply": ply.write(args.infile, mesh, binary=True) elif fmt == "stl": stl.write(args.infile, mesh, binary=True) elif fmt == "vtk": vtk.write(args.infile, mesh, binary=True) elif fmt == "vtu": vtu.write(args.infile, mesh, binary=True) elif fmt == "xdmf": xdmf.write(args.infile, mesh, data_format="HDF") else: print(f"Don't know how to convert {args.infile} to binary format.") exit(1) size = os.stat(args.infile).st_size print(f"File size after: {size / 1024 ** 2:.2f} MB") src/meshio/_cli/_compress.py000066400000000000000000000045271456244072500164240ustar00rootroot00000000000000import os import pathlib from .. import ansys, cgns, gmsh, h5m, mdpa, ply, stl, vtk, vtu, xdmf from .._common import error from .._helpers import _filetypes_from_path, read, reader_map def add_args(parser): parser.add_argument("infile", type=str, help="mesh file to compress") parser.add_argument( "--input-format", "-i", type=str, choices=sorted(list(reader_map.keys())), help="input file format", default=None, ) parser.add_argument( "--max", "-max", action="store_true", help="maximum compression", default=False, ) def compress(args): if args.input_format: fmts = [args.input_format] else: fmts = _filetypes_from_path(pathlib.Path(args.infile)) # pick the first fmt = fmts[0] size = os.stat(args.infile).st_size print(f"File size before: {size / 1024 ** 2:.2f} MB") mesh = read(args.infile, file_format=args.input_format) # # Some converters (like VTK) require `points` to be contiguous. # mesh.points = np.ascontiguousarray(mesh.points) # write it out if fmt == "ansys": ansys.write(args.infile, mesh, binary=True) elif fmt == "cgns": cgns.write( args.infile, mesh, compression="gzip", compression_opts=9 if args.max else 4 ) elif fmt == "gmsh": gmsh.write(args.infile, mesh, binary=True) elif fmt == "h5m": h5m.write( args.infile, mesh, compression="gzip", compression_opts=9 if args.max else 4 ) elif fmt == "mdpa": mdpa.write(args.infile, mesh, binary=True) elif fmt == "ply": ply.write(args.infile, mesh, binary=True) elif fmt == "stl": stl.write(args.infile, mesh, binary=True) elif fmt == "vtk": vtk.write(args.infile, mesh, binary=True) elif fmt == "vtu": vtu.write( args.infile, mesh, binary=True, compression="lzma" if args.max else "zlib" ) elif fmt == "xdmf": xdmf.write( args.infile, mesh, data_format="HDF", compression="gzip", compression_opts=9 if args.max else 4, ) else: error(f"Don't know how to compress {args.infile}.") exit(1) size = os.stat(args.infile).st_size print(f"File size after: {size / 1024 ** 2:.2f} MB") src/meshio/_cli/_convert.py000066400000000000000000000041751456244072500162500ustar00rootroot00000000000000import numpy as np from .._helpers import _writer_map, read, reader_map, write def add_args(parser): parser.add_argument("infile", type=str, help="mesh file to be read from") parser.add_argument( "--input-format", "-i", type=str, choices=sorted(list(reader_map.keys())), help="input file format", default=None, ) parser.add_argument( "--output-format", "-o", type=str, choices=sorted(list(_writer_map.keys())), help="output file format", default=None, ) parser.add_argument( "--ascii", "-a", action="store_true", help="write in ASCII format variant (where applicable, default: binary)", ) parser.add_argument("outfile", type=str, help="mesh file to be written to") parser.add_argument( "--float-format", "-f", type=str, help="float format used in output ASCII files (default: .16e)", ) parser.add_argument( "--sets-to-int-data", "-s", action="store_true", help="if possible, convert sets to integer data (useful if the output type does not support sets)", ) parser.add_argument( "--int-data-to-sets", "-d", action="store_true", help="if possible, convert integer data to sets (useful if the output type does not support integer data)", ) def convert(args): # read mesh data mesh = read(args.infile, file_format=args.input_format) # Some converters (like VTK) require `points` to be contiguous. mesh.points = np.ascontiguousarray(mesh.points) if args.sets_to_int_data: mesh.point_sets_to_data() mesh.cell_sets_to_data() if args.int_data_to_sets: for key in mesh.point_data: mesh.point_data_to_sets(key) for key in mesh.cell_data: mesh.cell_data_to_sets(key) # write it out kwargs = {"file_format": args.output_format} if args.float_format is not None: kwargs["float_fmt"] = args.float_format if args.ascii: kwargs["binary"] = False write(args.outfile, mesh, **kwargs) src/meshio/_cli/_decompress.py000066400000000000000000000027101456244072500167250ustar00rootroot00000000000000import os import pathlib from .. import cgns, h5m, vtu, xdmf from .._common import error from .._helpers import _filetypes_from_path, read, reader_map def add_args(parser): parser.add_argument("infile", type=str, help="mesh file to decompress") parser.add_argument( "--input-format", "-i", type=str, choices=sorted(list(reader_map.keys())), help="input file format", default=None, ) def decompress(args): if args.input_format: fmts = [args.input_format] else: fmts = _filetypes_from_path(pathlib.Path(args.infile)) # pick the first fmt = fmts[0] size = os.stat(args.infile).st_size print(f"File size before: {size / 1024 ** 2:.2f} MB") mesh = read(args.infile, file_format=args.input_format) # # Some converters (like VTK) require `points` to be contiguous. # mesh.points = np.ascontiguousarray(mesh.points) # write it out if fmt == "cgns": cgns.write(args.infile, mesh, compression=None) elif fmt == "h5m": h5m.write(args.infile, mesh, compression=None) elif fmt == "vtu": vtu.write(args.infile, mesh, binary=True, compression=None) elif fmt == "xdmf": xdmf.write(args.infile, mesh, data_format="HDF", compression=None) else: error(f"Don't know how to decompress {args.infile}.") exit(1) size = os.stat(args.infile).st_size print(f"File size after: {size / 1024 ** 2:.2f} MB") src/meshio/_cli/_info.py000066400000000000000000000021301456244072500155100ustar00rootroot00000000000000import numpy as np from .._common import warn from .._helpers import read, reader_map def add_args(parser): parser.add_argument("infile", type=str, help="mesh file to be read from") parser.add_argument( "--input-format", "-i", type=str, choices=sorted(list(reader_map.keys())), help="input file format", default=None, ) def info(args): # read mesh data mesh = read(args.infile, file_format=args.input_format) print(mesh) # check if the cell arrays are consistent with the points is_consistent = True for cells in mesh.cells: if np.any(cells.data > mesh.points.shape[0]): warn("Inconsistent mesh. Cells refer to nonexistent points.") is_consistent = False break # check if there are redundant points if is_consistent: point_is_used = np.zeros(mesh.points.shape[0], dtype=bool) for cells in mesh.cells: point_is_used[cells.data] = True if np.any(~point_is_used): warn("Some points are not part of any cell.") return 0 src/meshio/_cli/_main.py000066400000000000000000000036171456244072500155140ustar00rootroot00000000000000import argparse from sys import version_info from ..__about__ import __version__ from . import _ascii, _binary, _compress, _convert, _decompress, _info def main(argv=None): parent_parser = argparse.ArgumentParser( description="Mesh input/output tools.", formatter_class=argparse.RawTextHelpFormatter, ) parent_parser.add_argument( "--version", "-v", action="version", version=_get_version_text(), help="display version information", ) subparsers = parent_parser.add_subparsers( title="subcommands", dest="command", required=True ) parser = subparsers.add_parser("convert", help="Convert mesh files", aliases=["c"]) _convert.add_args(parser) parser.set_defaults(func=_convert.convert) parser = subparsers.add_parser("info", help="Print mesh info", aliases=["i"]) _info.add_args(parser) parser.set_defaults(func=_info.info) parser = subparsers.add_parser("compress", help="Compress mesh file") _compress.add_args(parser) parser.set_defaults(func=_compress.compress) parser = subparsers.add_parser("decompress", help="Decompress mesh file") _decompress.add_args(parser) parser.set_defaults(func=_decompress.decompress) parser = subparsers.add_parser("ascii", help="Convert to ASCII", aliases=["a"]) _ascii.add_args(parser) parser.set_defaults(func=_ascii.ascii) parser = subparsers.add_parser("binary", help="Convert to binary", aliases=["b"]) _binary.add_args(parser) parser.set_defaults(func=_binary.binary) args = parent_parser.parse_args(argv) return args.func(args) def _get_version_text(): python_version = f"{version_info.major}.{version_info.minor}.{version_info.micro}" return "\n".join( [ f"meshio {__version__} [Python {python_version}]", "Copyright (c) 2015-2021 Nico Schlömer et al.", ] ) src/meshio/_common.py000066400000000000000000000074531456244072500151540ustar00rootroot00000000000000from __future__ import annotations from xml.etree import ElementTree as ET import numpy as np from rich.console import Console # See for the node # ordering. num_nodes_per_cell = { "vertex": 1, "line": 2, "triangle": 3, "quad": 4, "quad8": 8, "tetra": 4, "hexahedron": 8, "hexahedron20": 20, "hexahedron24": 24, "wedge": 6, "pyramid": 5, # "line3": 3, "triangle6": 6, "quad9": 9, "tetra10": 10, "hexahedron27": 27, "wedge15": 15, "wedge18": 18, "pyramid13": 13, "pyramid14": 14, # "line4": 4, "triangle10": 10, "quad16": 16, "tetra20": 20, "wedge40": 40, "hexahedron64": 64, # "line5": 5, "triangle15": 15, "quad25": 25, "tetra35": 35, "wedge75": 75, "hexahedron125": 125, # "line6": 6, "triangle21": 21, "quad36": 36, "tetra56": 56, "wedge126": 126, "hexahedron216": 216, # "line7": 7, "triangle28": 28, "quad49": 49, "tetra84": 84, "wedge196": 196, "hexahedron343": 343, # "line8": 8, "triangle36": 36, "quad64": 64, "tetra120": 120, "wedge288": 288, "hexahedron512": 512, # "line9": 9, "triangle45": 45, "quad81": 81, "tetra165": 165, "wedge405": 405, "hexahedron729": 729, # "line10": 10, "triangle55": 55, "quad100": 100, "tetra220": 220, "wedge550": 550, "hexahedron1000": 1000, "hexahedron1331": 1331, # "line11": 11, "triangle66": 66, "quad121": 121, "tetra286": 286, } def cell_data_from_raw(cells, cell_data_raw): cs = np.cumsum([len(c) for c in cells])[:-1] return {name: np.split(d, cs) for name, d in cell_data_raw.items()} def raw_from_cell_data(cell_data): return {name: np.concatenate(value) for name, value in cell_data.items()} def write_xml(filename, root): tree = ET.ElementTree(root) tree.write(filename) def _pick_first_int_data(data): # pick out material keys = list(data.keys()) candidate_keys = [] for key in keys: # works for point_data and cell_data if data[key][0].dtype.kind in ["i", "u"]: # int or uint candidate_keys.append(key) if len(candidate_keys) > 0: # pick the first key = candidate_keys[0] idx = keys.index(key) other = keys[:idx] + keys[idx + 1 :] else: key = None other = [] return key, other def info(string, highlight: bool = True) -> None: Console(stderr=True).print(f"[bold]Info:[/bold] {string}", highlight=highlight) def warn(string, highlight: bool = True) -> None: Console(stderr=True).print( f"[yellow][bold]Warning:[/bold] {string}[/yellow]", highlight=highlight ) def error(string, highlight: bool = True) -> None: Console(stderr=True).print( f"[red][bold]Error:[/bold] {string}[/red]", highlight=highlight ) def is_in_any(string: str, strings: list[str]) -> bool: """True if `string` is contained in any of `strings`.""" for s in strings: if string in s: return True return False def join_strings(strings: list[str]) -> tuple[str, str]: """Join strings such that they can be uniquely split again afterwards.""" possible_join_chars = ["-", "_", "#", "+", "/"] char = None for c in possible_join_chars: if not is_in_any(c, strings): char = c break assert char is not None return char.join(strings), char def replace_space(string: str) -> tuple[str, str]: possible_chars = ["_", "-", "+", "X", "/", "#"] char = None for c in possible_chars: if c not in string: char = c break assert char is not None return string.replace(" ", char), char src/meshio/_cxml/000077500000000000000000000000001456244072500142445ustar00rootroot00000000000000src/meshio/_cxml/__init__.py000066400000000000000000000000511456244072500163510ustar00rootroot00000000000000from . import etree __all__ = ["etree"] src/meshio/_cxml/etree.py000066400000000000000000000035111456244072500157220ustar00rootroot00000000000000# This XML writer is a drop-in replacement for LXML/Python XML Etree. It only offers one # other member: self.text_write. # The problem is that, for LXML, the entire etree has to be constructed in memory before # writing it to a file. Many mesh formats that use XML have lots of int or float data # written in the text fields. Converting this to ASCII first requires a lot of memory. # This etree here allows the writing method to write to the file directly, without # having to create a string representation first. class Element: def __init__(self, name, **kwargs): self.name = name self.attrib = kwargs self._children = [] self.text = None self.text_writer = None def insert(self, pos, elem): self._children.insert(pos, elem) def set(self, key, value): self.attrib[key] = value def write(self, f): kw_list = [f'{key}="{value}"' for key, value in self.attrib.items()] f.write("<{}>\n".format(" ".join([self.name] + kw_list))) if self.text: f.write(self.text) f.write("\n") if self.text_writer: self.text_writer(f) f.write("\n") for child in self._children: child.write(f) f.write(f"\n") class SubElement(Element): def __init__(self, parent, name, **kwargs): super().__init__(name, **kwargs) parent._children.append(self) class Comment: def __init__(self, text): self.text = text def write(self, f): f.write(f"\n") class ElementTree: def __init__(self, root): self.root = root def write(self, filename, xml_declaration=True): with open(filename, "w") as f: if xml_declaration: f.write('\n') self.root.write(f) src/meshio/_exceptions.py000066400000000000000000000001721456244072500160340ustar00rootroot00000000000000class ReadError(Exception): pass class WriteError(Exception): pass class CorruptionError(Exception): pass src/meshio/_files.py000066400000000000000000000005551456244072500147620ustar00rootroot00000000000000from contextlib import contextmanager def is_buffer(obj, mode): return ("r" in mode and hasattr(obj, "read")) or ( "w" in mode and hasattr(obj, "write") ) @contextmanager def open_file(path_or_buf, mode="r"): if is_buffer(path_or_buf, mode): yield path_or_buf else: with open(path_or_buf, mode) as f: yield f src/meshio/_helpers.py000066400000000000000000000127371456244072500153270ustar00rootroot00000000000000from __future__ import annotations import sys from pathlib import Path import numpy as np from numpy.typing import ArrayLike from ._common import error, num_nodes_per_cell from ._exceptions import ReadError, WriteError from ._files import is_buffer from ._mesh import CellBlock, Mesh extension_to_filetypes = {} reader_map = {} _writer_map = {} def register_format( format_name: str, extensions: list[str], reader, writer_map ) -> None: for ext in extensions: if ext not in extension_to_filetypes: extension_to_filetypes[ext] = [] extension_to_filetypes[ext].append(format_name) if reader is not None: reader_map[format_name] = reader _writer_map.update(writer_map) def deregister_format(format_name: str): for value in extension_to_filetypes.values(): if format_name in value: value.remove(format_name) if format_name in reader_map: reader_map.pop(format_name) if format_name in _writer_map: _writer_map.pop(format_name) def _filetypes_from_path(path: Path) -> list[str]: ext = "" out = [] for suffix in reversed(path.suffixes): ext = (suffix + ext).lower() try: out += extension_to_filetypes[ext] except KeyError: pass if not out: raise ReadError(f"Could not deduce file format from path '{path}'.") return out def read(filename, file_format: str | None = None): """Reads an unstructured mesh with added data. :param filenames: The files/PathLikes to read from. :type filenames: str :returns mesh{2,3}d: The mesh data. """ if is_buffer(filename, "r"): return _read_buffer(filename, file_format) return _read_file(Path(filename), file_format) def _read_buffer(filename, file_format: str | None): if file_format is None: raise ReadError("File format must be given if buffer is used") if file_format == "tetgen": raise ReadError( "tetgen format is spread across multiple files " "and so cannot be read from a buffer" ) if file_format not in reader_map: raise ReadError(f"Unknown file format '{file_format}'") return reader_map[file_format](filename) def _read_file(path: Path, file_format: str | None): if not path.exists(): raise ReadError(f"File {path} not found.") if file_format: possible_file_formats = [file_format] else: # deduce possible file formats from extension possible_file_formats = _filetypes_from_path(path) for file_format in possible_file_formats: if file_format not in reader_map: raise ReadError(f"Unknown file format '{file_format}' of '{path}'.") try: return reader_map[file_format](str(path)) except ReadError as e: print(e) if len(possible_file_formats) == 1: msg = f"Couldn't read file {path} as {possible_file_formats[0]}" else: lst = ", ".join(possible_file_formats) msg = f"Couldn't read file {path} as either of {lst}" error(msg) sys.exit(1) def write_points_cells( filename, points: ArrayLike, cells: dict[str, ArrayLike] | list[tuple[str, ArrayLike] | CellBlock], point_data: dict[str, ArrayLike] | None = None, cell_data: dict[str, list[ArrayLike]] | None = None, field_data=None, point_sets: dict[str, ArrayLike] | None = None, cell_sets: dict[str, list[ArrayLike]] | None = None, file_format: str | None = None, **kwargs, ): points = np.asarray(points) mesh = Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data, point_sets=point_sets, cell_sets=cell_sets, ) mesh.write(filename, file_format=file_format, **kwargs) def write(filename, mesh: Mesh, file_format: str | None = None, **kwargs): """Writes mesh together with data to a file. :params filename: File to write to. :type filename: str :params point_data: Named additional point data to write to the file. :type point_data: dict """ if is_buffer(filename, "r"): if file_format is None: raise WriteError("File format must be supplied if `filename` is a buffer") if file_format == "tetgen": raise WriteError( "tetgen format is spread across multiple files, and so cannot be written to a buffer" ) else: path = Path(filename) if not file_format: # deduce possible file formats from extension file_formats = _filetypes_from_path(path) # just take the first one file_format = file_formats[0] try: writer = _writer_map[file_format] except KeyError: formats = sorted(list(_writer_map.keys())) raise WriteError(f"Unknown format '{file_format}'. Pick one of {formats}") # check cells for sanity for cell_block in mesh.cells: key = cell_block.type value = cell_block.data if key in num_nodes_per_cell: if value.shape[1] != num_nodes_per_cell[key]: raise WriteError( f"Unexpected cells array shape {value.shape} for {key} cells. " + f"Expected shape [:, {num_nodes_per_cell[key]}]." ) else: # we allow custom keys and # cannot check those pass # Write return writer(filename, mesh, **kwargs) src/meshio/_mesh.py000066400000000000000000000337111456244072500146140ustar00rootroot00000000000000from __future__ import annotations import copy import numpy as np from numpy.typing import ArrayLike from ._common import num_nodes_per_cell, warn topological_dimension = { "line": 1, "polygon": 2, "triangle": 2, "quad": 2, "tetra": 3, "hexahedron": 3, "wedge": 3, "pyramid": 3, "line3": 1, "triangle6": 2, "quad9": 2, "tetra10": 3, "hexahedron27": 3, "wedge18": 3, "pyramid14": 3, "vertex": 0, "quad8": 2, "hexahedron20": 3, "triangle10": 2, "triangle15": 2, "triangle21": 2, "line4": 1, "line5": 1, "line6": 1, "tetra20": 3, "tetra35": 3, "tetra56": 3, "quad16": 2, "quad25": 2, "quad36": 2, "triangle28": 2, "triangle36": 2, "triangle45": 2, "triangle55": 2, "triangle66": 2, "quad49": 2, "quad64": 2, "quad81": 2, "quad100": 2, "quad121": 2, "line7": 1, "line8": 1, "line9": 1, "line10": 1, "line11": 1, "tetra84": 3, "tetra120": 3, "tetra165": 3, "tetra220": 3, "tetra286": 3, "wedge40": 3, "wedge75": 3, "hexahedron64": 3, "hexahedron125": 3, "hexahedron216": 3, "hexahedron343": 3, "hexahedron512": 3, "hexahedron729": 3, "hexahedron1000": 3, "wedge126": 3, "wedge196": 3, "wedge288": 3, "wedge405": 3, "wedge550": 3, "VTK_LAGRANGE_CURVE": 1, "VTK_LAGRANGE_TRIANGLE": 2, "VTK_LAGRANGE_QUADRILATERAL": 2, "VTK_LAGRANGE_TETRAHEDRON": 3, "VTK_LAGRANGE_HEXAHEDRON": 3, "VTK_LAGRANGE_WEDGE": 3, "VTK_LAGRANGE_PYRAMID": 3, } class CellBlock: def __init__( self, cell_type: str, data: list | np.ndarray, tags: list[str] | None = None, ): self.type = cell_type self.data = data if cell_type.startswith("polyhedron"): self.dim = 3 else: self.data = np.asarray(self.data) self.dim = topological_dimension[cell_type] self.tags = [] if tags is None else tags def __repr__(self): items = [ "meshio CellBlock", f"type: {self.type}", f"num cells: {len(self.data)}", f"tags: {self.tags}", ] return "<" + ", ".join(items) + ">" def __len__(self): return len(self.data) class Mesh: def __init__( self, points: ArrayLike, cells: dict[str, ArrayLike] | list[tuple[str, ArrayLike] | CellBlock], point_data: dict[str, ArrayLike] | None = None, cell_data: dict[str, list[ArrayLike]] | None = None, field_data=None, point_sets: dict[str, ArrayLike] | None = None, cell_sets: dict[str, list[ArrayLike]] | None = None, gmsh_periodic=None, info=None, ): self.points = np.asarray(points) if isinstance(cells, dict): # Let's not deprecate this for now. # warn( # "cell dictionaries are deprecated, use list of tuples, e.g., " # '[("triangle", [[0, 1, 2], ...])]', # DeprecationWarning, # ) # old dict, deprecated # # convert dict to list of tuples cells = list(cells.items()) self.cells = [] for cell_block in cells: if isinstance(cell_block, tuple): cell_type, data = cell_block cell_block = CellBlock( cell_type, # polyhedron data cannot be converted to numpy arrays # because the sublists don't all have the same length data if cell_type.startswith("polyhedron") else np.asarray(data), ) self.cells.append(cell_block) self.point_data = {} if point_data is None else point_data self.cell_data = {} if cell_data is None else cell_data self.field_data = {} if field_data is None else field_data self.point_sets = {} if point_sets is None else point_sets self.cell_sets = {} if cell_sets is None else cell_sets self.gmsh_periodic = gmsh_periodic self.info = info # assert point data consistency and convert to numpy arrays for key, item in self.point_data.items(): self.point_data[key] = np.asarray(item) if len(self.point_data[key]) != len(self.points): raise ValueError( f"len(points) = {len(self.points)}, " f'but len(point_data["{key}"]) = {len(self.point_data[key])}' ) # assert cell data consistency and convert to numpy arrays for key, data in self.cell_data.items(): if len(data) != len(cells): raise ValueError( f"Incompatible cell data '{key}'. " f"{len(cells)} cell blocks, but '{key}' has {len(data)} blocks." ) for k in range(len(data)): data[k] = np.asarray(data[k]) if len(data[k]) != len(self.cells[k]): raise ValueError( "Incompatible cell data. " + f"Cell block {k} ('{self.cells[k].type}') " + f"has length {len(self.cells[k])}, but " + f"corresponding cell data item has length {len(data[k])}." ) def __repr__(self): lines = ["", f" Number of points: {len(self.points)}"] special_cells = [ "polygon", "polyhedron", "VTK_LAGRANGE_CURVE", "VTK_LAGRANGE_TRIANGLE", "VTK_LAGRANGE_QUADRILATERAL", "VTK_LAGRANGE_TETRAHEDRON", "VTK_LAGRANGE_HEXAHEDRON", "VTK_LAGRANGE_WEDGE", "VTK_LAGRANGE_PYRAMID", ] if len(self.cells) > 0: lines.append(" Number of cells:") for cell_block in self.cells: string = cell_block.type if cell_block.type in special_cells: string += f"({cell_block.data.shape[1]})" lines.append(f" {string}: {len(cell_block)}") else: lines.append(" No cells.") if self.point_sets: names = ", ".join(self.point_sets.keys()) lines.append(f" Point sets: {names}") if self.cell_sets: names = ", ".join(self.cell_sets.keys()) lines.append(f" Cell sets: {names}") if self.point_data: names = ", ".join(self.point_data.keys()) lines.append(f" Point data: {names}") if self.cell_data: names = ", ".join(self.cell_data.keys()) lines.append(f" Cell data: {names}") if self.field_data: names = ", ".join(self.field_data.keys()) lines.append(f" Field data: {names}") return "\n".join(lines) def copy(self): return copy.deepcopy(self) def write(self, path_or_buf, file_format: str | None = None, **kwargs): # avoid circular import from ._helpers import write write(path_or_buf, self, file_format, **kwargs) def get_cells_type(self, cell_type: str): if not any(c.type == cell_type for c in self.cells): return np.empty((0, num_nodes_per_cell[cell_type]), dtype=int) return np.concatenate([c.data for c in self.cells if c.type == cell_type]) def get_cell_data(self, name: str, cell_type: str): return np.concatenate( [d for c, d in zip(self.cells, self.cell_data[name]) if c.type == cell_type] ) @property def cells_dict(self): cells_dict = {} for cell_block in self.cells: if cell_block.type not in cells_dict: cells_dict[cell_block.type] = [] cells_dict[cell_block.type].append(cell_block.data) # concatenate for key, value in cells_dict.items(): cells_dict[key] = np.concatenate(value) return cells_dict @property def cell_data_dict(self): cell_data_dict = {} for key, value_list in self.cell_data.items(): cell_data_dict[key] = {} for value, cell_block in zip(value_list, self.cells): if cell_block.type not in cell_data_dict[key]: cell_data_dict[key][cell_block.type] = [] cell_data_dict[key][cell_block.type].append(value) for cell_type, val in cell_data_dict[key].items(): cell_data_dict[key][cell_type] = np.concatenate(val) return cell_data_dict @property def cell_sets_dict(self): sets_dict = {} for key, member_list in self.cell_sets.items(): sets_dict[key] = {} offsets = {} for members, cells in zip(member_list, self.cells): if members is None: continue if cells.type in offsets: offset = offsets[cells.type] offsets[cells.type] += cells.data.shape[0] else: offset = 0 offsets[cells.type] = cells.data.shape[0] if cells.type in sets_dict[key]: sets_dict[key][cells.type].append(members + offset) else: sets_dict[key][cells.type] = [members + offset] return { key: { cell_type: np.concatenate(members) for cell_type, members in sets.items() if sum(map(np.size, members)) } for key, sets in sets_dict.items() } @classmethod def read(cls, path_or_buf, file_format=None): # avoid circular import from ._helpers import read # 2021-02-21 warn("meshio.Mesh.read is deprecated, use meshio.read instead") return read(path_or_buf, file_format) def cell_sets_to_data(self, data_name: str | None = None): # If possible, convert cell sets to integer cell data. This is possible if all # cells appear exactly in one group. default_value = -1 if len(self.cell_sets) > 0: intfun = [] for k, c in enumerate(zip(*self.cell_sets.values())): # Go for -1 as the default value. (NaN is not int.) arr = np.full(len(self.cells[k]), default_value, dtype=int) for i, cc in enumerate(c): if cc is None: continue arr[cc] = i intfun.append(arr) for item in intfun: num_default = np.sum(item == default_value) if num_default > 0: warn( f"{num_default} cells are not part of any cell set. " f"Using default value {default_value}." ) break if data_name is None: data_name = "-".join(self.cell_sets.keys()) self.cell_data[data_name] = intfun self.cell_sets = {} def point_sets_to_data(self, join_char: str = "-") -> None: # now for the point sets # Go for -1 as the default value. (NaN is not int.) default_value = -1 if len(self.point_sets) > 0: intfun = np.full(len(self.points), default_value, dtype=int) for i, cc in enumerate(self.point_sets.values()): intfun[cc] = i if np.any(intfun == default_value): warn( "Not all points are part of a point set. " f"Using default value {default_value}." ) data_name = join_char.join(self.point_sets.keys()) self.point_data[data_name] = intfun self.point_sets = {} # This used to be int_data_to_sets(), converting _all_ cell and point data. # This is not useful in many cases, as one usually only wants one # particular data array (e.g., "MaterialIDs") converted to sets. def cell_data_to_sets(self, key: str): """Convert point_data to cell_sets.""" data = self.cell_data[key] # handle all int and uint data if not all(v.dtype.kind in ["i", "u"] for v in data): raise RuntimeError(f"cell_data['{key}'] is not int data.") tags = np.unique(np.concatenate(data)) # try and get the names by splitting the key along "-" (this is how # sets_to_int_data() forms the key) names = key.split("-") # remove duplicates and preserve order # : names = list(dict.fromkeys(names)) if len(names) != len(tags): # alternative names names = [f"set-{key}-{tag}" for tag in tags] # TODO there's probably a better way besides np.where, something from # np.unique or np.sort for name, tag in zip(names, tags): self.cell_sets[name] = [np.where(d == tag)[0] for d in data] # remove the cell data del self.cell_data[key] def point_data_to_sets(self, key: str): """Convert point_data to point_sets.""" data = self.point_data[key] # handle all int and uint data if not all(v.dtype.kind in ["i", "u"] for v in data): raise RuntimeError(f"point_data['{key}'] is not int data.") tags = np.unique(data) # try and get the names by splitting the key along "-" (this is how # sets_to_int_data() forms the key names = key.split("-") # remove duplicates and preserve order # : names = list(dict.fromkeys(names)) if len(names) != len(tags): # alternative names names = [f"set-key-{tag}" for tag in tags] # TODO there's probably a better way besides np.where, something from # np.unique or np.sort for name, tag in zip(names, tags): self.point_sets[name] = np.where(data == tag)[0] # remove the cell data del self.point_data[key] src/meshio/_vtk_common.py000066400000000000000000000157211456244072500160350ustar00rootroot00000000000000import numpy as np from ._common import num_nodes_per_cell, warn from ._exceptions import ReadError from ._mesh import CellBlock # https://vtk.org/doc/nightly/html/vtkCellType_8h_source.html vtk_to_meshio_type = { 0: "empty", 1: "vertex", # 2: 'poly_vertex', 3: "line", # 4: 'poly_line', 5: "triangle", # 6: 'triangle_strip', 7: "polygon", 8: "pixel", 9: "quad", 10: "tetra", # 11: 'voxel', 12: "hexahedron", 13: "wedge", 14: "pyramid", 15: "penta_prism", 16: "hexa_prism", 21: "line3", 22: "triangle6", 23: "quad8", 24: "tetra10", 25: "hexahedron20", 26: "wedge15", 27: "pyramid13", 28: "quad9", 29: "hexahedron27", 30: "quad6", 31: "wedge12", 32: "wedge18", 33: "hexahedron24", 34: "triangle7", 35: "line4", 42: "polyhedron", # # 60: VTK_HIGHER_ORDER_EDGE, # 61: VTK_HIGHER_ORDER_TRIANGLE, # 62: VTK_HIGHER_ORDER_QUAD, # 63: VTK_HIGHER_ORDER_POLYGON, # 64: VTK_HIGHER_ORDER_TETRAHEDRON, # 65: VTK_HIGHER_ORDER_WEDGE, # 66: VTK_HIGHER_ORDER_PYRAMID, # 67: VTK_HIGHER_ORDER_HEXAHEDRON, # Arbitrary order Lagrange elements 68: "VTK_LAGRANGE_CURVE", 69: "VTK_LAGRANGE_TRIANGLE", 70: "VTK_LAGRANGE_QUADRILATERAL", 71: "VTK_LAGRANGE_TETRAHEDRON", 72: "VTK_LAGRANGE_HEXAHEDRON", 73: "VTK_LAGRANGE_WEDGE", 74: "VTK_LAGRANGE_PYRAMID", # Arbitrary order Bezier elements 75: "VTK_BEZIER_CURVE", 76: "VTK_BEZIER_TRIANGLE", 77: "VTK_BEZIER_QUADRILATERAL", 78: "VTK_BEZIER_TETRAHEDRON", 79: "VTK_BEZIER_HEXAHEDRON", 80: "VTK_BEZIER_WEDGE", 81: "VTK_BEZIER_PYRAMID", } meshio_to_vtk_type = {v: k for k, v in vtk_to_meshio_type.items()} def vtk_to_meshio_order(vtk_type, dtype=int): # meshio uses the same node ordering as VTK for most cell types. However, for the # linear wedge, the ordering of the gmsh Prism [1] is adopted since this is found in # most codes (Abaqus, Ansys, Nastran,...). In the vtkWedge [2], the normal of the # (0,1,2) triangle points outwards, while in gmsh this normal points inwards. # [1] http://gmsh.info/doc/texinfo/gmsh.html#Node-ordering # [2] https://vtk.org/doc/nightly/html/classvtkWedge.html if vtk_type == 13: return np.array([0, 2, 1, 3, 5, 4], dtype=dtype) return None def meshio_to_vtk_order(meshio_type, dtype=int): if meshio_type == "wedge": return np.array([0, 2, 1, 3, 5, 4], dtype=dtype) return None def vtk_cells_from_data(connectivity, offsets, types, cell_data_raw): # Translate it into the cells array. # `connectivity` is a one-dimensional vector with # (p00, p01, ... ,p0k, p10, p11, ..., p1k, ... # `offsets` is a pointer array that points to the first position of p0, p1, etc. if len(offsets) != len(types): raise ReadError(f"len(offsets) != len(types) ({len(offsets)} != {len(types)})") # identify cell blocks breaks = np.where(types[:-1] != types[1:])[0] + 1 # all cells with indices between start[k] and end[k] have the same type start_end = list( zip( np.concatenate([[0], breaks]), np.concatenate([breaks, [len(types)]]), ) ) cells = [] cell_data = {} for start, end in start_end: try: meshio_type = vtk_to_meshio_type[types[start]] except KeyError: warn( f"File contains cells that meshio cannot handle (type {types[start]})." ) continue # cells with varying number of points special_cells = [ "polygon", "VTK_LAGRANGE_CURVE", "VTK_LAGRANGE_TRIANGLE", "VTK_LAGRANGE_QUADRILATERAL", "VTK_LAGRANGE_TETRAHEDRON", "VTK_LAGRANGE_HEXAHEDRON", "VTK_LAGRANGE_WEDGE", "VTK_LAGRANGE_PYRAMID", ] if meshio_type in special_cells: # Polygons have unknown and varying number of nodes per cell. # Index where the previous block of cells stopped. Needed to know the number # of nodes for the first cell in the block. first_node = 0 if start == 0 else offsets[start - 1] # Start off the cell-node relation for each cell in this block start_cn = np.hstack((first_node, offsets[start:end])) # Find the size of each cell except the last sizes = np.diff(start_cn) # find where the cell blocks start and end b = np.diff(sizes) c = np.concatenate([[0], np.where(b != 0)[0] + 1, [len(sizes)]]) # Loop over all cell sizes, find all cells with this size, and assign # connectivity for cell_block_start, cell_block_end in zip(c, c[1:]): items = np.arange(cell_block_start, cell_block_end) sz = sizes[cell_block_start] new_order = vtk_to_meshio_order(types[start], dtype=offsets.dtype) if new_order is None: new_order = np.arange(sz, dtype=offsets.dtype) new_order -= sz indices = np.add.outer(start_cn[items + 1], new_order) cells.append(CellBlock(meshio_type, connectivity[indices])) # Store cell data for this set of cells for name, d in cell_data_raw.items(): if name not in cell_data: cell_data[name] = [] cell_data[name].append(d[start + items]) else: # Non-polygonal cell. Same number of nodes per cell makes everything easier. n = num_nodes_per_cell[meshio_type] new_order = vtk_to_meshio_order(types[start], dtype=offsets.dtype) if new_order is None: new_order = np.arange(n, dtype=offsets.dtype) new_order -= n indices = np.add.outer(offsets[start:end], new_order) cells.append(CellBlock(meshio_type, connectivity[indices])) for name, d in cell_data_raw.items(): if name not in cell_data: cell_data[name] = [] cell_data[name].append(d[start:end]) return cells, cell_data class Info: """Info Container for the VTK reader.""" def __init__(self): self.points = None self.field_data = {} self.cell_data_raw = {} self.point_data = {} self.dataset = {} self.connectivity = None self.offsets = None self.types = None self.active = None self.is_ascii = False self.split = [] self.num_items = 0 # One of the problem in reading VTK files are POINT_DATA and CELL_DATA fields. # They can contain a number of SCALARS+LOOKUP_TABLE tables, without giving and # indication of how many there are. Hence, SCALARS must be treated like a # first-class section. To associate it with POINT/CELL_DATA, we store the # `active` section in this variable. self.section = None src/meshio/abaqus/000077500000000000000000000000001456244072500144165ustar00rootroot00000000000000src/meshio/abaqus/__init__.py000066400000000000000000000000761456244072500165320ustar00rootroot00000000000000from ._abaqus import read, write __all__ = ["read", "write"] src/meshio/abaqus/_abaqus.py000066400000000000000000000324421456244072500164100ustar00rootroot00000000000000""" I/O for Abaqus inp files. """ import pathlib from itertools import count import numpy as np from ..__about__ import __version__ from .._common import num_nodes_per_cell from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh abaqus_to_meshio_type = { # trusses "T2D2": "line", "T2D2H": "line", "T2D3": "line3", "T2D3H": "line3", "T3D2": "line", "T3D2H": "line", "T3D3": "line3", "T3D3H": "line3", # beams "B21": "line", "B21H": "line", "B22": "line3", "B22H": "line3", "B31": "line", "B31H": "line", "B32": "line3", "B32H": "line3", "B33": "line3", "B33H": "line3", # surfaces "CPS4": "quad", "CPS4R": "quad", "S4": "quad", "S4R": "quad", "S4RS": "quad", "S4RSW": "quad", "S4R5": "quad", "S8R": "quad8", "S8R5": "quad8", "S9R5": "quad9", # "QUAD": "quad", # "QUAD4": "quad", # "QUAD5": "quad5", # "QUAD8": "quad8", # "QUAD9": "quad9", # "CPS3": "triangle", "STRI3": "triangle", "S3": "triangle", "S3R": "triangle", "S3RS": "triangle", "R3D3": "triangle", # "TRI7": "triangle7", # 'TRISHELL': 'triangle', # 'TRISHELL3': 'triangle', # 'TRISHELL7': 'triangle', # "STRI65": "triangle6", # 'TRISHELL6': 'triangle6', # volumes "C3D8": "hexahedron", "C3D8H": "hexahedron", "C3D8I": "hexahedron", "C3D8IH": "hexahedron", "C3D8R": "hexahedron", "C3D8RH": "hexahedron", # "HEX9": "hexahedron9", "C3D20": "hexahedron20", "C3D20H": "hexahedron20", "C3D20R": "hexahedron20", "C3D20RH": "hexahedron20", # "HEX27": "hexahedron27", # "C3D4": "tetra", "C3D4H": "tetra4", # "TETRA8": "tetra8", "C3D10": "tetra10", "C3D10H": "tetra10", "C3D10I": "tetra10", "C3D10M": "tetra10", "C3D10MH": "tetra10", # "TETRA14": "tetra14", # # "PYRAMID": "pyramid", "C3D6": "wedge", "C3D15": "wedge15", # # 4-node bilinear displacement and pore pressure "CAX4P": "quad", # 6-node quadratic "CPE6": "triangle6", } meshio_to_abaqus_type = {v: k for k, v in abaqus_to_meshio_type.items()} def read(filename): """Reads a Abaqus inp file.""" with open_file(filename, "r") as f: out = read_buffer(f) return out def read_buffer(f): # Initialize the optional data fields points = [] cells = [] cell_ids = [] point_sets = {} cell_sets = {} cell_sets_element = {} # Handle cell sets defined in ELEMENT cell_sets_element_order = [] # Order of keys is not preserved in Python 3.5 field_data = {} cell_data = {} point_data = {} point_ids = None line = f.readline() while True: if not line: # EOF break # Comments if line.startswith("**"): line = f.readline() continue keyword = line.partition(",")[0].strip().replace("*", "").upper() if keyword == "NODE": points, point_ids, line = _read_nodes(f) elif keyword == "ELEMENT": if point_ids is None: raise ReadError("Expected NODE before ELEMENT") params_map = get_param_map(line, required_keys=["TYPE"]) cell_type, cells_data, ids, sets, line = _read_cells( f, params_map, point_ids ) cells.append(CellBlock(cell_type, cells_data)) cell_ids.append(ids) if sets: cell_sets_element.update(sets) cell_sets_element_order += list(sets.keys()) elif keyword == "NSET": params_map = get_param_map(line, required_keys=["NSET"]) set_ids, _, line = _read_set(f, params_map) name = params_map["NSET"] point_sets[name] = np.array( [point_ids[point_id] for point_id in set_ids], dtype="int32" ) elif keyword == "ELSET": params_map = get_param_map(line, required_keys=["ELSET"]) set_ids, set_names, line = _read_set(f, params_map) name = params_map["ELSET"] cell_sets[name] = [] if set_ids.size: for cell_ids_ in cell_ids: cell_sets_ = np.array( [ cell_ids_[set_id] for set_id in set_ids if set_id in cell_ids_ ], dtype="int32", ) cell_sets[name].append(cell_sets_) elif set_names: for set_name in set_names: if set_name in cell_sets.keys(): cell_sets[name].append(cell_sets[set_name]) elif set_name in cell_sets_element.keys(): cell_sets[name].append(cell_sets_element[set_name]) else: raise ReadError(f"Unknown cell set '{set_name}'") elif keyword == "INCLUDE": # Splitting line to get external input file path (example: *INCLUDE,INPUT=wInclude_bulk.inp) ext_input_file = pathlib.Path(line.split("=")[-1].strip()) if ext_input_file.exists() is False: cd = pathlib.Path(f.name).parent ext_input_file = cd / ext_input_file # Read contents from external input file into mesh object out = read(ext_input_file) # Merge contents of external file only if it is containing mesh data if len(out.points) > 0: points, cells = merge( out, points, cells, point_data, cell_data, field_data, point_sets, cell_sets, ) line = f.readline() else: # There are just too many Abaqus keywords to explicitly skip them. line = f.readline() # Parse cell sets defined in ELEMENT for i, name in enumerate(cell_sets_element_order): # Not sure whether this case would ever happen if name in cell_sets.keys(): cell_sets[name][i] = cell_sets_element[name] else: cell_sets[name] = [] for ic in range(len(cells)): cell_sets[name].append( cell_sets_element[name] if i == ic else np.array([], dtype="int32") ) return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data, point_sets=point_sets, cell_sets=cell_sets, ) def _read_nodes(f): points = [] point_ids = {} counter = 0 while True: line = f.readline() if not line or line.startswith("*"): break if line.strip() == "": continue line = line.strip().split(",") point_id, coords = line[0], line[1:] point_ids[int(point_id)] = counter points.append([float(x) for x in coords]) counter += 1 return np.array(points, dtype=float), point_ids, line def _read_cells(f, params_map, point_ids): etype = params_map["TYPE"] if etype not in abaqus_to_meshio_type.keys(): raise ReadError(f"Element type not available: {etype}") cell_type = abaqus_to_meshio_type[etype] # ElementID + NodesIDs num_data = num_nodes_per_cell[cell_type] + 1 idx = [] while True: line = f.readline() if not line or line.startswith("*"): break line = line.strip() if line == "": continue idx += [int(k) for k in filter(None, line.split(","))] # Check for expected number of data if len(idx) % num_data != 0: raise ReadError("Expected number of data items does not match element type") idx = np.array(idx).reshape((-1, num_data)) cell_ids = dict(zip(idx[:, 0], count(0))) cells = np.array([[point_ids[node] for node in elem] for elem in idx[:, 1:]]) cell_sets = ( {params_map["ELSET"]: np.arange(len(cells), dtype="int32")} if "ELSET" in params_map.keys() else {} ) return cell_type, cells, cell_ids, cell_sets, line def merge( mesh, points, cells, point_data, cell_data, field_data, point_sets, cell_sets ): """ Merge Mesh object into existing containers for points, cells, sets, etc.. :param mesh: :param points: :param cells: :param point_data: :param cell_data: :param field_data: :param point_sets: :param cell_sets: :type mesh: Mesh """ ext_points = np.array([p for p in mesh.points]) if len(points) > 0: new_point_id = points.shape[0] # new_cell_id = len(cells) + 1 points = np.concatenate([points, ext_points]) else: # new_cell_id = 0 new_point_id = 0 points = ext_points cnt = 0 for c in mesh.cells: new_data = np.array([d + new_point_id for d in c.data]) cells.append(CellBlock(c.type, new_data)) cnt += 1 # The following aren't currently included in the abaqus parser, and are therefore # excluded? # point_data.update(mesh.point_data) # cell_data.update(mesh.cell_data) # field_data.update(mesh.field_data) # Update point and cell sets to account for change in cell and point ids for key, val in mesh.point_sets.items(): point_sets[key] = [x + new_point_id for x in val] # Todo: Add support for merging cell sets # cellblockref = [[] for i in range(cnt-new_cell_id)] # for key, val in mesh.cell_sets.items(): # cell_sets[key] = cellblockref + [np.array([x for x in val[0]])] return points, cells def get_param_map(word, required_keys=None): """ get the optional arguments on a line Example ------- >>> word = 'elset,instance=dummy2,generate' >>> params = get_param_map(word, required_keys=['instance']) params = { 'elset' : None, 'instance' : 'dummy2, 'generate' : None, } """ if required_keys is None: required_keys = [] words = word.split(",") param_map = {} for wordi in words: if "=" not in wordi: key = wordi.strip().upper() value = None else: sword = wordi.split("=") if len(sword) != 2: raise ReadError(sword) key = sword[0].strip().upper() value = sword[1].strip() param_map[key] = value msg = "" for key in required_keys: if key not in param_map: msg += f"{key} not found in {word}\n" if msg: raise RuntimeError(msg) return param_map def _read_set(f, params_map): set_ids = [] set_names = [] while True: line = f.readline() if not line or line.startswith("*"): break if line.strip() == "": continue line = line.strip().strip(",").split(",") if line[0].isnumeric(): set_ids += [int(k) for k in line] else: set_names.append(line[0]) set_ids = np.array(set_ids, dtype="int32") if "GENERATE" in params_map: if len(set_ids) != 3: raise ReadError(set_ids) set_ids = np.arange(set_ids[0], set_ids[1] + 1, set_ids[2], dtype="int32") return set_ids, set_names, line def write( filename, mesh: Mesh, float_fmt: str = ".16e", translate_cell_names: bool = True ) -> None: with open_file(filename, "wt") as f: f.write("*HEADING\n") f.write("Abaqus DataFile Version 6.14\n") f.write(f"written by meshio v{__version__}\n") f.write("*NODE\n") fmt = ", ".join(["{}"] + ["{:" + float_fmt + "}"] * mesh.points.shape[1]) + "\n" for k, x in enumerate(mesh.points): f.write(fmt.format(k + 1, *x)) eid = 0 for cell_block in mesh.cells: cell_type = cell_block.type node_idcs = cell_block.data name = ( meshio_to_abaqus_type[cell_type] if translate_cell_names else cell_type ) f.write(f"*ELEMENT, TYPE={name}\n") for row in node_idcs: eid += 1 nids_strs = (str(nid + 1) for nid in row.tolist()) f.write(str(eid) + "," + ",".join(nids_strs) + "\n") nnl = 8 offset = 0 for ic in range(len(mesh.cells)): for k, v in mesh.cell_sets.items(): if len(v[ic]) > 0: els = [str(i + 1 + offset) for i in v[ic]] f.write(f"*ELSET, ELSET={k}\n") f.write( ",\n".join( ",".join(els[i : i + nnl]) for i in range(0, len(els), nnl) ) + "\n" ) offset += len(mesh.cells[ic].data) for k, v in mesh.point_sets.items(): nds = [str(i + 1) for i in v] f.write(f"*NSET, NSET={k}\n") f.write( ",\n".join(",".join(nds[i : i + nnl]) for i in range(0, len(nds), nnl)) + "\n" ) # https://github.com/nschloe/meshio/issues/747#issuecomment-643479921 # f.write("*END") register_format("abaqus", [".inp"], read, {"abaqus": write}) src/meshio/ansys/000077500000000000000000000000001456244072500142775ustar00rootroot00000000000000src/meshio/ansys/__init__.py000066400000000000000000000000751456244072500164120ustar00rootroot00000000000000from ._ansys import read, write __all__ = ["read", "write"] src/meshio/ansys/_ansys.py000066400000000000000000000360051456244072500161510ustar00rootroot00000000000000""" I/O for Ansys's msh format. """ import re import numpy as np from ..__about__ import __version__ from .._common import warn from .._exceptions import ReadError, WriteError from .._files import open_file from .._helpers import register_format from .._mesh import Mesh def _skip_to(f, char): c = None while c != char: c = f.read(1).decode() def _skip_close(f, num_open_brackets): while num_open_brackets > 0: char = f.read(1).decode() if char == "(": num_open_brackets += 1 elif char == ")": num_open_brackets -= 1 def _read_points(f, line, first_point_index_overall, last_point_index): # If the line is self-contained, it is merely a declaration # of the total number of points. if line.count("(") == line.count(")"): return None, None, None # (3010 (zone-id first-index last-index type ND) out = re.match("\\s*\\(\\s*(|20|30)10\\s*\\(([^\\)]*)\\).*", line) assert out is not None a = [int(num, 16) for num in out.group(2).split()] if len(a) <= 4: raise ReadError() first_point_index = a[1] # store the very first point index if first_point_index_overall is None: first_point_index_overall = first_point_index # make sure that point arrays are subsequent if last_point_index is not None: if last_point_index + 1 != first_point_index: raise ReadError() last_point_index = a[2] num_points = last_point_index - first_point_index + 1 dim = a[4] # Skip ahead to the byte that opens the data block (might # be the current line already). last_char = line.strip()[-1] while last_char != "(": last_char = f.read(1).decode() if out.group(1) == "": # ASCII data pts = np.empty((num_points, dim)) for k in range(num_points): # skip ahead to the first line with data line = "" while line.strip() == "": line = f.readline().decode() dat = line.split() if len(dat) != dim: raise ReadError() for d in range(dim): pts[k][d] = float(dat[d]) else: # binary data if out.group(1) == "20": dtype = np.float32 else: if out.group(1) != "30": ReadError(f"Expected keys '20' or '30', got {out.group(1)}.") dtype = np.float64 # read point data pts = np.fromfile(f, count=dim * num_points, dtype=dtype).reshape( (num_points, dim) ) # make sure that the data set is properly closed _skip_close(f, 2) return pts, first_point_index_overall, last_point_index def _read_cells(f, line): # If the line is self-contained, it is merely a declaration of the total number of # points. if line.count("(") == line.count(")"): return None, None out = re.match("\\s*\\(\\s*(|20|30)12\\s*\\(([^\\)]+)\\).*", line) assert out is not None a = [int(num, 16) for num in out.group(2).split()] if len(a) <= 4: raise ReadError() first_index = a[1] last_index = a[2] num_cells = last_index - first_index + 1 zone_type = a[3] element_type = a[4] if zone_type == 0: # dead zone return None, None key, num_nodes_per_cell = { 0: ("mixed", None), 1: ("triangle", 3), 2: ("tetra", 4), 3: ("quad", 4), 4: ("hexahedron", 8), 5: ("pyramid", 5), 6: ("wedge", 6), }[element_type] # Skip to the opening `(` and make sure that there's no non-whitespace character # between the last closing bracket and the `(`. if line.strip()[-1] != "(": c = None while True: c = f.read(1).decode() if c == "(": break if not re.match("\\s", c): # Found a non-whitespace character before `(`. # Assume this is just a declaration line then and # skip to the closing bracket. _skip_to(f, ")") return None, None if key == "mixed": # From # : # # > If a zone is of mixed type (element-type=0), it will have a body that # > lists the element type of each cell. # # No idea where the information other than the element types is stored # though. Skip for now. data = None else: # read cell data if out.group(1) == "": # ASCII cells data = np.empty((num_cells, num_nodes_per_cell), dtype=int) for k in range(num_cells): line = f.readline().decode() dat = line.split() if len(dat) != num_nodes_per_cell: raise ReadError() data[k] = [int(d, 16) for d in dat] else: if key == "mixed": raise ReadError("Cannot read mixed cells in binary mode yet") # binary cells if out.group(1) == "20": dtype = np.int32 else: if out.group(1) != "30": ReadError(f"Expected keys '20' or '30', got {out.group(1)}.") dtype = np.int64 shape = (num_cells, num_nodes_per_cell) count = shape[0] * shape[1] data = np.fromfile(f, count=count, dtype=dtype).reshape(shape) # make sure that the data set is properly closed _skip_close(f, 2) return key, data def _read_faces(f, line): # faces # (13 (zone-id first-index last-index type element-type)) # If the line is self-contained, it is merely a declaration of # the total number of points. if line.count("(") == line.count(")"): return {} out = re.match("\\s*\\(\\s*(|20|30)13\\s*\\(([^\\)]+)\\).*", line) assert out is not None a = [int(num, 16) for num in out.group(2).split()] if len(a) <= 4: raise ReadError() first_index = a[1] last_index = a[2] num_cells = last_index - first_index + 1 element_type = a[4] element_type_to_key_num_nodes = { 0: ("mixed", None), 2: ("line", 2), 3: ("triangle", 3), 4: ("quad", 4), } key, num_nodes_per_cell = element_type_to_key_num_nodes[element_type] # Skip ahead to the line that opens the data block (might be # the current line already). if line.strip()[-1] != "(": _skip_to(f, "(") data = {} if out.group(1) == "": # ASCII if key == "mixed": # From # : # # > If the face zone is of mixed type (element-type = > 0), the body of the # > section will include the face type and will appear as follows # > # > type v0 v1 v2 c0 c1 # > for k in range(num_cells): line = "" while line.strip() == "": line = f.readline().decode() dat = line.split() type_index = int(dat[0], 16) if type_index == 0: raise ReadError() type_string, num_nodes_per_cell = element_type_to_key_num_nodes[ type_index ] if len(dat) != num_nodes_per_cell + 3: raise ReadError() if type_string not in data: data[type_string] = [] data[type_string].append( [int(d, 16) for d in dat[1 : num_nodes_per_cell + 1]] ) data = {key: np.array(data[key]) for key in data} else: # read cell data data = np.empty((num_cells, num_nodes_per_cell), dtype=int) for k in range(num_cells): line = f.readline().decode() dat = line.split() # The body of a regular face section contains the grid connectivity, and # each line appears as follows: # n0 n1 n2 cr cl # where n* are the defining nodes (vertices) of the face, and c* are the # adjacent cells. if len(dat) != num_nodes_per_cell + 2: raise ReadError() data[k] = [int(d, 16) for d in dat[:num_nodes_per_cell]] data = {key: data} else: # binary if out.group(1) == "20": dtype = np.int32 else: if out.group(1) != "30": ReadError(f"Expected keys '20' or '30', got {out.group(1)}.") dtype = np.int64 if key == "mixed": raise ReadError("Mixed element type for binary faces not supported yet") # Read cell data. # The body of a regular face section contains the grid # connectivity, and each line appears as follows: # n0 n1 n2 cr cl # where n* are the defining nodes (vertices) of the face, # and c* are the adjacent cells. shape = (num_cells, num_nodes_per_cell + 2) count = shape[0] * shape[1] data = np.fromfile(f, count=count, dtype=dtype).reshape(shape) # Cut off the adjacent cell data. data = data[:, :num_nodes_per_cell] data = {key: data} # make sure that the data set is properly closed _skip_close(f, 2) return data def read(filename): # noqa: C901 # Initialize the data optional data fields field_data = {} cell_data = {} point_data = {} points = [] cells = [] first_point_index_overall = None last_point_index = None # read file in binary mode since some data might be binary with open_file(filename, "rb") as f: while True: line = f.readline().decode() if not line: break if line.strip() == "": continue # expect the line to have the form # ( [...] out = re.match("\\s*\\(\\s*([0-9]+).*", line) if not out: raise ReadError() index = out.group(1) if index == "0": # Comment. _skip_close(f, line.count("(") - line.count(")")) elif index == "1": # header # (1 "") _skip_close(f, line.count("(") - line.count(")")) elif index == "2": # dimensionality # (2 3) _skip_close(f, line.count("(") - line.count(")")) elif re.match("(|20|30)10", index): # points pts, first_point_index_overall, last_point_index = _read_points( f, line, first_point_index_overall, last_point_index ) if pts is not None: points.append(pts) elif re.match("(|20|30)12", index): # cells # (2012 (zone-id first-index last-index type element-type)) key, data = _read_cells(f, line) if data is not None: cells.append((key, data)) elif re.match("(|20|30)13", index): data = _read_faces(f, line) for key in data: cells.append((key, data[key])) elif index == "39": warn("Zone specification not supported yet. Skipping.") _skip_close(f, line.count("(") - line.count(")")) elif index == "45": # (45 (2 fluid solid)()) obj = re.match("\\(45 \\([0-9]+ ([\\S]+) ([\\S]+)\\)\\(\\)\\)", line) if obj: warn( f"Zone specification not supported yet ({obj.group(1)}, {obj.group(2)}). " + "Skipping.", ) else: warn("Zone specification not supported yet.") else: warn(f"Unknown index {index}. Skipping.") # Skipping ahead to the next line with two closing brackets. _skip_close(f, line.count("(") - line.count(")")) points = np.concatenate(points) # Gauge the cells with the first point_index. for k, c in enumerate(cells): cells[k] = (c[0], c[1] - first_point_index_overall) return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data ) def write(filename, mesh, binary=True): with open_file(filename, "wb") as fh: # header fh.write(f'(1 "meshio {__version__}")\n'.encode()) # dimension num_points, dim = mesh.points.shape if dim not in [2, 3]: raise WriteError(f"Can only write dimension 2, 3, got {dim}.") fh.write((f"(2 {dim})\n").encode()) # total number of nodes first_node_index = 1 fh.write((f"(10 (0 {first_node_index:x} {num_points:x} 0))\n").encode()) # total number of cells total_num_cells = sum(len(c) for c in mesh.cells) fh.write((f"(12 (0 1 {total_num_cells:x} 0))\n").encode()) # Write nodes key = "3010" if binary else "10" fh.write( f"({key} (1 {first_node_index:x} {num_points:x} 1 {dim:x})(\n".encode() ) if binary: mesh.points.tofile(fh) fh.write(b"\n)") fh.write(b"End of Binary Section 3010)\n") else: np.savetxt(fh, mesh.points, fmt="%.16e") fh.write(b"))\n") # Write cells meshio_to_ansys_type = { # "mixed": 0, "triangle": 1, "tetra": 2, "quad": 3, "hexahedron": 4, "pyramid": 5, "wedge": 6, # "polyhedral": 7, } first_index = 0 binary_dtypes = { # np.int16 is not allowed np.dtype("int32"): "2012", np.dtype("int64"): "3012", } for cell_block in mesh.cells: cell_type = cell_block.type values = cell_block.data key = binary_dtypes[values.dtype] if binary else "12" last_index = first_index + len(values) - 1 try: ansys_cell_type = meshio_to_ansys_type[cell_type] except KeyError: legal_keys = ", ".join(meshio_to_ansys_type.keys()) raise KeyError( f"Illegal ANSYS cell type '{cell_type}'. (legal: {legal_keys})" ) fh.write( f"({key} (1 {first_index:x} {last_index:x} 1 {ansys_cell_type})(\n".encode() ) if binary: (values + first_node_index).tofile(fh) fh.write(b"\n)") fh.write((f"End of Binary Section {key})\n").encode()) else: np.savetxt(fh, values + first_node_index, fmt="%x") fh.write(b"))\n") first_index = last_index + 1 register_format("ansys", [".msh"], read, {"ansys": write}) src/meshio/avsucd/000077500000000000000000000000001456244072500144275ustar00rootroot00000000000000src/meshio/avsucd/__init__.py000066400000000000000000000000761456244072500165430ustar00rootroot00000000000000from ._avsucd import read, write __all__ = ["read", "write"] src/meshio/avsucd/_avsucd.py000066400000000000000000000163261456244072500164350ustar00rootroot00000000000000""" I/O for AVS-UCD format, cf. . """ import numpy as np from ..__about__ import __version__ as version from .._common import _pick_first_int_data, warn from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh meshio_to_avsucd_type = { "vertex": "pt", "line": "line", "triangle": "tri", "quad": "quad", "tetra": "tet", "pyramid": "pyr", "wedge": "prism", "hexahedron": "hex", } avsucd_to_meshio_type = {v: k for k, v in meshio_to_avsucd_type.items()} meshio_to_avsucd_order = { "vertex": [0], "line": [0, 1], "triangle": [0, 1, 2], "quad": [0, 1, 2, 3], "tetra": [0, 1, 3, 2], "pyramid": [4, 0, 1, 2, 3], "wedge": [3, 4, 5, 0, 1, 2], "hexahedron": [4, 5, 6, 7, 0, 1, 2, 3], } avsucd_to_meshio_order = { k: (v if k != "pyramid" else [1, 2, 3, 4, 0]) for k, v in meshio_to_avsucd_order.items() } def read(filename): with open_file(filename, "r") as f: out = read_buffer(f) return out def read_buffer(f): # Skip comments and unpack first line num_nodes, num_cells, num_node_data, num_cell_data, _ = np.genfromtxt( f, max_rows=1, dtype=int, comments="#" ) # Read nodes point_ids, points = _read_nodes(f, num_nodes) # Read cells cell_ids, cells, cell_data = _read_cells(f, num_cells, point_ids) # Read node data if num_node_data: point_data = _read_data(f, num_nodes, point_ids) else: point_data = {} # Read cell data if num_cell_data: cdata = _read_data(f, num_cells, cell_ids) sections = np.cumsum([len(c[1]) for c in cells[:-1]]) for k, v in cdata.items(): cell_data[k] = np.split(v, sections) return Mesh(points, cells, point_data=point_data, cell_data=cell_data) def _read_nodes(f, num_nodes): if num_nodes > 0: data = np.genfromtxt(f, max_rows=num_nodes) else: data = np.empty((0, 3)) points_ids = {int(pid): i for i, pid in enumerate(data[:, 0])} return points_ids, data[:, 1:] def _read_cells(f, num_cells, point_ids): cells = [] cell_ids = {} cell_data = {"avsucd:material": []} count = 0 for _ in range(num_cells): line = f.readline().strip().split() cell_id = int(line[0]) cell_mat = int(line[1]) cell_type = avsucd_to_meshio_type[line[2]] corner = [point_ids[int(pid)] for pid in line[3:]] if len(cells) > 0 and cells[-1][0] == cell_type: cells[-1][1].append(corner) cell_data["avsucd:material"][-1].append(cell_mat) else: cells.append((cell_type, [corner])) cell_data["avsucd:material"].append([cell_mat]) cell_ids[cell_id] = count count += 1 # Convert to numpy arrays for k, (cell_type, cdata) in enumerate(cells): cells[k] = CellBlock( cell_type, np.array(cdata)[:, avsucd_to_meshio_order[cell_type]] ) cell_data["avsucd:material"][k] = np.array(cell_data["avsucd:material"][k]) return cell_ids, cells, cell_data def _read_data(f, num_entities, entity_ids): line = f.readline().strip().split() data_size = [int(i) for i in line[1:]] labels = {} data = {} for i, dsize in enumerate(data_size): line = f.readline().strip().split(",") labels[i] = line[0].strip().replace(" ", "_") data[labels[i]] = ( np.empty(num_entities) if dsize == 1 else np.empty((num_entities, dsize)) ) for _ in range(num_entities): line = f.readline().strip().split() eid = entity_ids[int(line[0])] j = 0 for i, dsize in enumerate(data_size): if dsize == 1: data[labels[i]][eid] = float(line[j + 1]) else: data[labels[i]][eid] = [ float(val) for val in line[j + 1 : j + 1 + dsize] ] j += dsize return data def write(filename, mesh): if len(mesh.points.shape) > 1 and mesh.points.shape[1] == 2: warn( "AVS-UCD requires 3D points, but 2D points given. " "Appending 0 third component." ) mesh.points = np.column_stack([mesh.points, np.zeros_like(mesh.points[:, 0])]) with open_file(filename, "w") as f: # Write meshio version f.write(f"# Written by meshio v{version}\n") # Write first line num_nodes = len(mesh.points) num_cells = sum(len(c.data) for c in mesh.cells) # Try to find an appropriate materials array key, other = _pick_first_int_data(mesh.cell_data) if key and other: other_string = ", ".join(other) warn( "AVS-UCD can only write one cell data array. " f"Picking {key}, skipping {other_string}." ) material = ( np.concatenate(mesh.cell_data[key]) if key else np.zeros(num_cells, dtype=int) ) num_node_data = [ 1 if v.ndim == 1 else v.shape[1] for v in mesh.point_data.values() ] num_cell_data = [ 1 if np.concatenate(v).ndim == 1 else np.concatenate(v).shape[1] for k, v in mesh.cell_data.items() if k != key ] num_node_data_sum = sum(num_node_data) num_cell_data_sum = sum(num_cell_data) f.write(f"{num_nodes} {num_cells} {num_node_data_sum} {num_cell_data_sum} 0\n") # Write nodes _write_nodes(f, mesh.points) # Write cells _write_cells(f, mesh.cells, material) # Write node data if num_node_data_sum: labels = mesh.point_data.keys() data_array = np.column_stack([v for v in mesh.point_data.values()]) _write_data( f, labels, data_array, num_nodes, num_node_data, num_node_data_sum ) # Write cell data if num_cell_data_sum: labels = [k for k in mesh.cell_data.keys() if k != key] data_array = np.column_stack( [np.concatenate(v) for k, v in mesh.cell_data.items() if k != key] ) _write_data( f, labels, data_array, num_cells, num_cell_data, num_cell_data_sum ) def _write_nodes(f, points): for i, (x, y, z) in enumerate(points): f.write(f"{i + 1} {x} {y} {z}\n") def _write_cells(f, cells, material): i = 0 for cell_block in cells: cell_type = cell_block.type v = cell_block.data for cell in v[:, meshio_to_avsucd_order[cell_type]]: cell_str = " ".join(str(c) for c in cell + 1) f.write( f"{i + 1} {material[i]} {meshio_to_avsucd_type[cell_type]} {cell_str}\n" ) i += 1 def _write_data(f, labels, data_array, num_entities, num_data, num_data_sum): num_data_str = " ".join(str(i) for i in num_data) f.write(f"{len(num_data)} {num_data_str}\n") for label in labels: f.write(f"{label}, real\n") data_array = np.column_stack((np.arange(1, num_entities + 1), data_array)) np.savetxt(f, data_array, delimiter=" ", fmt=["%d"] + ["%.14e"] * num_data_sum) register_format("avsucd", [".avs"], read, {"avsucd": write}) src/meshio/cgns/000077500000000000000000000000001456244072500140745ustar00rootroot00000000000000src/meshio/cgns/__init__.py000066400000000000000000000000741456244072500162060ustar00rootroot00000000000000from ._cgns import read, write __all__ = ["read", "write"] src/meshio/cgns/_cgns.py000066400000000000000000000056061456244072500155460ustar00rootroot00000000000000""" CGNS TODO link to specification? """ import numpy as np from .._exceptions import ReadError from .._helpers import register_format from .._mesh import Mesh def read(filename): import h5py f = h5py.File(filename, "r") if "Base" not in f: raise ReadError('Expected "Base" in file. Malformed CGNS?') if "Zone1" not in f["Base"]: raise ReadError('Expected "Zone1" in "Base". Malformed CGNS?') x = f["Base"]["Zone1"]["GridCoordinates"]["CoordinateX"][" data"] y = f["Base"]["Zone1"]["GridCoordinates"]["CoordinateY"][" data"] z = f["Base"]["Zone1"]["GridCoordinates"]["CoordinateZ"][" data"] points = np.column_stack([x, y, z]) # f["Base"]["Zone1"]["GridElements"]["ElementRange"][" data"]) idx_min, idx_max = f["Base"]["Zone1"]["GridElements"]["ElementRange"][" data"] data = f["Base"]["Zone1"]["GridElements"]["ElementConnectivity"][" data"] cells = np.array(data).reshape(idx_max, -1) - 1 # TODO how to distinguish cell types? if cells.shape[1] != 4: raise ReadError("Can only read tetrahedra.") cells = [("tetra", cells)] return Mesh(points, cells) def write(filename, mesh, compression="gzip", compression_opts=4): import h5py f = h5py.File(filename, "w") base = f.create_group("Base") # TODO something is missing here zone1 = base.create_group("Zone1") coords = zone1.create_group("GridCoordinates") # write points coord_x = coords.create_group("CoordinateX") coord_x.create_dataset( " data", data=mesh.points[:, 0], compression=compression, compression_opts=compression_opts, ) coord_y = coords.create_group("CoordinateY") coord_y.create_dataset( " data", data=mesh.points[:, 1], compression=compression, compression_opts=compression_opts, ) coord_z = coords.create_group("CoordinateZ") coord_z.create_dataset( " data", data=mesh.points[:, 2], compression=compression, compression_opts=compression_opts, ) # write cells # TODO write cells other than tetra elems = zone1.create_group("GridElements") rnge = elems.create_group("ElementRange") for cell_block in mesh.cells: if cell_block.type == "tetra": rnge.create_dataset( " data", data=[1, cell_block.data.shape[0]], compression=compression, compression_opts=compression_opts, ) conn = elems.create_group("ElementConnectivity") for cell_block in mesh.cells: if cell_block.type == "tetra": conn.create_dataset( " data", data=cell_block.data.reshape(-1) + 1, compression=compression, compression_opts=compression_opts, ) register_format("cgns", [".cgns"], read, {"cgns": write}) src/meshio/dolfin/000077500000000000000000000000001456244072500144155ustar00rootroot00000000000000src/meshio/dolfin/__init__.py000066400000000000000000000000761456244072500165310ustar00rootroot00000000000000from ._dolfin import read, write __all__ = ["read", "write"] src/meshio/dolfin/_dolfin.py000066400000000000000000000176531456244072500164150ustar00rootroot00000000000000""" I/O for DOLFIN's XML format, cf. . """ import os import pathlib import re from xml.etree import ElementTree as ET import numpy as np from .._common import warn from .._exceptions import ReadError, WriteError from .._helpers import register_format from .._mesh import Mesh def _read_mesh(filename): dolfin_to_meshio_type = {"triangle": ("triangle", 3), "tetrahedron": ("tetra", 4)} # Use iterparse() to avoid loading the entire file via parse(). iterparse() # allows to discard elements (via clear()) after they have been processed. # See . dim = None points = None keys = None cell_type = None num_nodes_per_cell = None cells = None cell_tags = None for event, elem in ET.iterparse(filename, events=("start", "end")): if event == "end": continue if elem.tag == "dolfin": # Don't be too strict with the assertion. Some mesh files don't have the # proper tags. # assert elem.attrib['nsmap'] \ # == '{\'dolfin\': \'https://fenicsproject.org/\'}' pass elif elem.tag == "mesh": dim = int(elem.attrib["dim"]) cell_type, num_nodes_per_cell = dolfin_to_meshio_type[ elem.attrib["celltype"] ] cell_tags = [f"v{i}" for i in range(num_nodes_per_cell)] elif elem.tag == "vertices": if dim is None: raise ReadError("Expected `mesh` before `vertices`") points = np.empty((int(elem.attrib["size"]), dim)) keys = ["x", "y"] if dim == 3: keys += ["z"] elif elem.tag == "vertex": if points is None or keys is None: raise ReadError("Expected `vertices` before `vertex`") k = int(elem.attrib["index"]) points[k] = [elem.attrib[key] for key in keys] elif elem.tag == "cells": if cell_type is None or num_nodes_per_cell is None: raise ReadError("Expected `mesh` before `cells`") cells = [ ( cell_type, np.empty((int(elem.attrib["size"]), num_nodes_per_cell), dtype=int), ) ] elif elem.tag in ["triangle", "tetrahedron"]: k = int(elem.attrib["index"]) assert cells is not None assert cell_tags is not None cells[0][1][k] = [elem.attrib[t] for t in cell_tags] else: warn(f"Unknown entry {elem.tag}. Ignoring.") elem.clear() return points, cells, cell_type def _read_cell_data(filename): dolfin_type_to_numpy_type = { "int": np.dtype("int"), "float": np.dtype("float"), "uint": np.dtype("uint"), } cell_data = {} dir_name = pathlib.Path(filename).resolve().parent # Loop over all files in the same directory as `filename`. basename = pathlib.Path(filename).stem for f in os.listdir(dir_name): # Check if there are files by the name "_*.xml"; if yes, # extract the * pattern and make it the name of the data set. out = re.match(f"{basename}_([^\\.]+)\\.xml", f) if not out: continue name = out.group(1) parser = ET.XMLParser() tree = ET.parse((dir_name / f).as_posix(), parser) root = tree.getroot() mesh_functions = list(root) if len(mesh_functions) != 1: raise ReadError("Can only handle one mesh function") mesh_function = mesh_functions[0] if mesh_function.tag != "mesh_function": raise ReadError() size = int(mesh_function.attrib["size"]) dtype = dolfin_type_to_numpy_type[mesh_function.attrib["type"]] data = np.empty(size, dtype=dtype) for child in mesh_function: if child.tag != "entity": raise ReadError() idx = int(child.attrib["index"]) data[idx] = child.attrib["value"] if name not in cell_data: cell_data[name] = [] cell_data[name].append(data) return cell_data def read(filename): points, cells, _ = _read_mesh(filename) cell_data = _read_cell_data(filename) return Mesh(points, cells, cell_data=cell_data) def _write_mesh(filename, points, cell_type, cells): stripped_cells = [c for c in cells if c.type == cell_type] meshio_to_dolfin_type = {"triangle": "triangle", "tetra": "tetrahedron"} if any(c.type != cell_type for c in cells): discarded_cell_types = {c.type for c in cells if c.type != cell_type} warn( "DOLFIN XML can only handle one cell type at a time. " + f"Using {cell_type}, discarding {', '.join(discarded_cell_types)}.", ) dim = points.shape[1] if dim not in [2, 3]: raise WriteError(f"Can only write dimension 2, 3, got {dim}.") coord_names = ["x", "y"] if dim == 3: coord_names += ["z"] with open(filename, "w") as f: f.write("\n") ct = meshio_to_dolfin_type[cell_type] f.write(f' \n') num_points = len(points) f.write(f' \n') for idx, point in enumerate(points): s = " ".join(f'{xyz}="{p}"' for xyz, p in zip("xyz", point)) f.write(f' \n') f.write(" \n") num_cells = 0 for c in stripped_cells: num_cells += len(c.data) f.write(f' \n') idx = 0 for cell_block in stripped_cells: type_string = meshio_to_dolfin_type[cell_block.type] for cell in cell_block.data: s = " ".join(f'v{k}="{c}"' for k, c in enumerate(cell)) f.write(f' <{type_string} index="{idx}" {s} />\n') idx += 1 f.write(" \n") f.write(" \n") f.write("") def _numpy_type_to_dolfin_type(dtype): types = { "int": [np.int8, np.int16, np.int32, np.int64], "uint": [np.uint8, np.uint16, np.uint32, np.uint64], "float": [np.float16, np.float32, np.float64], } for key, numpy_types in types.items(): for numpy_type in numpy_types: if np.issubdtype(dtype, numpy_type): return key raise WriteError("Could not convert NumPy data type to DOLFIN data type.") def _write_cell_data(filename, dim, cell_data): dolfin = ET.Element("dolfin", nsmap={"dolfin": "https://fenicsproject.org/"}) mesh_function = ET.SubElement( dolfin, "mesh_function", type=_numpy_type_to_dolfin_type(cell_data.dtype), dim=str(dim), size=str(len(cell_data)), ) for k, value in enumerate(cell_data): ET.SubElement(mesh_function, "entity", index=str(k), value=repr(value)) tree = ET.ElementTree(dolfin) tree.write(filename) def write(filename, mesh): warn("DOLFIN XML is a legacy format. Consider using XDMF instead.") if any("tetra" == c.type for c in mesh.cells): cell_type = "tetra" elif any("triangle" == c.type for c in mesh.cells): cell_type = "triangle" else: raise WriteError( "DOLFIN XML only supports triangles and tetrahedra. " "Consider using XDMF instead." ) _write_mesh(filename, mesh.points, cell_type, mesh.cells) for name, lst in mesh.cell_data.items(): for data in lst: fname = os.path.splitext(filename)[0] cell_data_filename = f"{fname}_{name}.xml" dim = 2 if mesh.points.shape[1] == 2 or all(mesh.points[:, 2] == 0) else 3 _write_cell_data(cell_data_filename, dim, np.array(data)) register_format("dolfin-xml", [".xml"], read, {"dolfin-xml": write}) src/meshio/exodus/000077500000000000000000000000001456244072500144515ustar00rootroot00000000000000src/meshio/exodus/__init__.py000066400000000000000000000000761456244072500165650ustar00rootroot00000000000000from ._exodus import read, write __all__ = ["read", "write"] src/meshio/exodus/_exodus.py000066400000000000000000000314211456244072500164720ustar00rootroot00000000000000""" I/O for Exodus II. See , in particular Appendix A (page 171, Implementation of EXODUS II with netCDF). """ import datetime import re import numpy as np from ..__about__ import __version__ from .._common import warn from .._exceptions import ReadError from .._helpers import register_format from .._mesh import Mesh exodus_to_meshio_type = { "SPHERE": "vertex", # curves "BEAM": "line", "BEAM2": "line", "BEAM3": "line3", "BAR2": "line", # surfaces "SHELL": "quad", "SHELL4": "quad", "SHELL8": "quad8", "SHELL9": "quad9", "QUAD": "quad", "QUAD4": "quad", "QUAD5": "quad5", "QUAD8": "quad8", "QUAD9": "quad9", # "TRI": "triangle", "TRIANGLE": "triangle", "TRI3": "triangle", "TRI6": "triangle6", "TRI7": "triangle7", # 'TRISHELL': 'triangle', # 'TRISHELL3': 'triangle', # 'TRISHELL6': 'triangle6', # 'TRISHELL7': 'triangle', # # volumes "HEX": "hexahedron", "HEXAHEDRON": "hexahedron", "HEX8": "hexahedron", "HEX9": "hexahedron9", "HEX20": "hexahedron20", "HEX27": "hexahedron27", # "TETRA": "tetra", "TETRA4": "tetra4", "TET4": "tetra4", "TETRA8": "tetra8", "TETRA10": "tetra10", "TETRA14": "tetra14", # "PYRAMID": "pyramid", "WEDGE": "wedge", } meshio_to_exodus_type = {v: k for k, v in exodus_to_meshio_type.items()} def read(filename): # noqa: C901 import netCDF4 with netCDF4.Dataset(filename) as nc: # assert nc.version == np.float32(5.1) # assert nc.api_version == np.float32(5.1) # assert nc.floating_point_word_size == 8 # assert b''.join(nc.variables['coor_names'][0]) == b'X' # assert b''.join(nc.variables['coor_names'][1]) == b'Y' # assert b''.join(nc.variables['coor_names'][2]) == b'Z' points = np.zeros((len(nc.dimensions["num_nodes"]), 3)) point_data_names = [] cell_data_names = [] pd = {} cd = {} cells = [] ns_names = [] # eb_names = [] ns = [] point_sets = {} info = [] for key, value in nc.variables.items(): if key == "info_records": value.set_auto_mask(False) for c in value[:]: try: info += [b"".join(c).decode("UTF-8")] except UnicodeDecodeError: # https://github.com/nschloe/meshio/issues/983 pass elif key == "qa_records": value.set_auto_mask(False) for val in value: info += [b"".join(c).decode("UTF-8") for c in val[:]] elif key[:7] == "connect": meshio_type = exodus_to_meshio_type[value.elem_type.upper()] cells.append((meshio_type, value[:] - 1)) elif key == "coord": points = nc.variables["coord"][:].T elif key == "coordx": points[:, 0] = value[:] elif key == "coordy": points[:, 1] = value[:] elif key == "coordz": points[:, 2] = value[:] elif key == "name_nod_var": value.set_auto_mask(False) point_data_names = [b"".join(c).decode("UTF-8") for c in value[:]] elif key[:12] == "vals_nod_var": idx = 0 if len(key) == 12 else int(key[12:]) - 1 value.set_auto_mask(False) # For now only take the first value pd[idx] = value[0] if len(value) > 1: warn("Skipping some time data") elif key == "name_elem_var": value.set_auto_mask(False) cell_data_names = [b"".join(c).decode("UTF-8") for c in value[:]] elif key[:13] == "vals_elem_var": # eb: element block m = re.match("vals_elem_var(\\d+)?(?:eb(\\d+))?", key) idx = 0 if m.group(1) is None else int(m.group(1)) - 1 block = 0 if m.group(2) is None else int(m.group(2)) - 1 value.set_auto_mask(False) # For now only take the first value if idx not in cd: cd[idx] = {} cd[idx][block] = value[0] if len(value) > 1: warn("Skipping some time data") elif key == "ns_names": value.set_auto_mask(False) ns_names = [b"".join(c).decode("UTF-8") for c in value[:]] # elif key == "eb_names": # value.set_auto_mask(False) # eb_names = [b"".join(c).decode("UTF-8") for c in value[:]] elif key.startswith("node_ns"): # Expected keys: node_ns1, node_ns2 ns.append(value[:] - 1) # Exodus is 1-based # merge element block data; can't handle blocks yet for k, value in cd.items(): cd[k] = np.concatenate(list(value.values())) # Check if there are any R, Z tuples or X, Y, Z # triplets in the point data. If yes, they belong together. single, double, triple = categorize(point_data_names) point_data = {} for name, idx in single: point_data[name] = pd[idx] for name, idx0, idx1 in double: point_data[name] = np.column_stack([pd[idx0], pd[idx1]]) for name, idx0, idx1, idx2 in triple: point_data[name] = np.column_stack([pd[idx0], pd[idx1], pd[idx2]]) cell_data = {} k = 0 for _, cell in cells: n = len(cell) for name, data in zip(cell_data_names, cd.values()): if name not in cell_data: cell_data[name] = [] cell_data[name].append(data[k : k + n]) k += n point_sets = {name: dat for name, dat in zip(ns_names, ns)} return Mesh( points, cells, point_data=point_data, cell_data=cell_data, point_sets=point_sets, info=info, ) def categorize(names): # Check if there are any R, Z tuples or X, Y, Z # triplets in the point data. If yes, they belong together. single = [] double = [] triple = [] is_accounted_for = [False] * len(names) k = 0 while True: if k == len(names): break if is_accounted_for[k]: k += 1 continue name = names[k] if name[-1] == "X": ix = k try: iy = names.index(name[:-1] + "Y") except ValueError: iy = None try: iz = names.index(name[:-1] + "Z") except ValueError: iz = None if iy and iz: triple.append((name[:-1], ix, iy, iz)) is_accounted_for[ix] = True is_accounted_for[iy] = True is_accounted_for[iz] = True else: single.append((name, ix)) is_accounted_for[ix] = True elif name[-2:] == "_R": ir = k try: iz = names.index(name[:-2] + "_Z") except ValueError: iz = None if iz: double.append((name[:-2], ir, iz)) is_accounted_for[ir] = True is_accounted_for[iz] = True else: single.append((name, ir)) is_accounted_for[ir] = True else: single.append((name, k)) is_accounted_for[k] = True k += 1 if not all(is_accounted_for): raise ReadError() return single, double, triple numpy_to_exodus_dtype = { "float32": "f4", "float64": "f8", "int8": "i1", "int16": "i2", "int32": "i4", "int64": "i8", "uint8": "u1", "uint16": "u2", "uint32": "u4", "uint64": "u8", } def write(filename, mesh): import netCDF4 with netCDF4.Dataset(filename, "w") as rootgrp: # set global data now = datetime.datetime.now().isoformat() rootgrp.title = f"Created by meshio v{__version__}, {now}" rootgrp.version = np.float32(5.1) rootgrp.api_version = np.float32(5.1) rootgrp.floating_point_word_size = 8 # set dimensions total_num_elems = sum(c.data.shape[0] for c in mesh.cells) rootgrp.createDimension("num_nodes", len(mesh.points)) rootgrp.createDimension("num_dim", mesh.points.shape[1]) rootgrp.createDimension("num_elem", total_num_elems) rootgrp.createDimension("num_el_blk", len(mesh.cells)) rootgrp.createDimension("num_node_sets", len(mesh.point_sets)) rootgrp.createDimension("len_string", 33) rootgrp.createDimension("len_line", 81) rootgrp.createDimension("four", 4) rootgrp.createDimension("time_step", None) # dummy time step data = rootgrp.createVariable("time_whole", "f4", ("time_step",)) data[:] = 0.0 # points coor_names = rootgrp.createVariable( "coor_names", "S1", ("num_dim", "len_string") ) coor_names.set_auto_mask(False) coor_names[0, 0] = b"X" coor_names[1, 0] = b"Y" if mesh.points.shape[1] == 3: coor_names[2, 0] = b"Z" data = rootgrp.createVariable( "coord", numpy_to_exodus_dtype[mesh.points.dtype.name], ("num_dim", "num_nodes"), ) data[:] = mesh.points.T # cells # ParaView needs eb_prop1 -- some ID. The values don't seem to matter as # long as they are different for the for different blocks. data = rootgrp.createVariable("eb_prop1", "i4", "num_el_blk") for k in range(len(mesh.cells)): data[k] = k for k, cell_block in enumerate(mesh.cells): dim1 = f"num_el_in_blk{k + 1}" dim2 = f"num_nod_per_el{k + 1}" rootgrp.createDimension(dim1, cell_block.data.shape[0]) rootgrp.createDimension(dim2, cell_block.data.shape[1]) dtype = numpy_to_exodus_dtype[cell_block.data.dtype.name] data = rootgrp.createVariable(f"connect{k + 1}", dtype, (dim1, dim2)) data.elem_type = meshio_to_exodus_type[cell_block.type] # Exodus is 1-based data[:] = cell_block.data + 1 # point data # The variable `name_nod_var` holds the names and indices of the node variables, the # variables `vals_nod_var{1,2,...}` hold the actual data. num_nod_var = len(mesh.point_data) if num_nod_var > 0: rootgrp.createDimension("num_nod_var", num_nod_var) # set names point_data_names = rootgrp.createVariable( "name_nod_var", "S1", ("num_nod_var", "len_string") ) point_data_names.set_auto_mask(False) for k, name in enumerate(mesh.point_data.keys()): for i, letter in enumerate(name): point_data_names[k, i] = letter.encode() # Set data. ParaView might have some problems here, see # . for k, (name, data) in enumerate(mesh.point_data.items()): for i, s in enumerate(data.shape): rootgrp.createDimension(f"dim_nod_var{k}{i}", s) dims = ["time_step"] + [ f"dim_nod_var{k}{i}" for i in range(len(data.shape)) ] node_data = rootgrp.createVariable( f"vals_nod_var{k + 1}", numpy_to_exodus_dtype[data.dtype.name], tuple(dims), fill_value=False, ) node_data[0] = data # node sets num_point_sets = len(mesh.point_sets) if num_point_sets > 0: data = rootgrp.createVariable("ns_prop1", "i4", "num_node_sets") data_names = rootgrp.createVariable( "ns_names", "S1", ("num_node_sets", "len_string") ) for k, name in enumerate(mesh.point_sets.keys()): data[k] = k for i, letter in enumerate(name): data_names[k, i] = letter.encode() for k, (key, values) in enumerate(mesh.point_sets.items()): dim1 = f"num_nod_ns{k + 1}" rootgrp.createDimension(dim1, values.shape[0]) dtype = numpy_to_exodus_dtype[values.dtype.name] data = rootgrp.createVariable(f"node_ns{k + 1}", dtype, (dim1,)) # Exodus is 1-based data[:] = values + 1 register_format("exodus", [".e", ".exo", ".ex2"], read, {"exodus": write}) src/meshio/flac3d/000077500000000000000000000000001456244072500142765ustar00rootroot00000000000000src/meshio/flac3d/__init__.py000066400000000000000000000000761456244072500164120ustar00rootroot00000000000000from ._flac3d import read, write __all__ = ["read", "write"] src/meshio/flac3d/_flac3d.py000066400000000000000000000443461456244072500161560ustar00rootroot00000000000000""" I/O for FLAC3D format. """ from __future__ import annotations import re import struct import time import numpy as np from ..__about__ import __version__ as version from .._common import warn from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import Mesh meshio_only = { "zone": { "tetra": "tetra", "tetra10": "tetra", "pyramid": "pyramid", "pyramid13": "pyramid", "wedge": "wedge", "wedge12": "wedge", "wedge15": "wedge", "wedge18": "wedge", "hexahedron": "hexahedron", "hexahedron20": "hexahedron", "hexahedron24": "hexahedron", "hexahedron27": "hexahedron", }, "face": { "triangle": "triangle", "triangle6": "triangle", "triangle7": "triangle", "quad": "quad", "quad8": "quad", "quad9": "quad", }, } numnodes_to_meshio_type = { "zone": {4: "tetra", 5: "pyramid", 6: "wedge", 8: "hexahedron"}, "face": {3: "triangle", 4: "quad"}, } meshio_to_flac3d_type = { "triangle": "T3", "quad": "Q4", "tetra": "T4", "pyramid": "P5", "wedge": "W6", "hexahedron": "B8", } flac3d_to_meshio_order = { "triangle": [0, 1, 2], "quad": [0, 1, 2, 3], "tetra": [0, 1, 2, 3], "pyramid": [0, 1, 4, 2, 3], "wedge": [0, 1, 3, 2, 4, 5], "hexahedron": [0, 1, 4, 2, 3, 6, 7, 5], } meshio_to_flac3d_order = { "triangle": [0, 1, 2], "quad": [0, 1, 2, 3], "tetra": [0, 1, 2, 3], "pyramid": [0, 1, 3, 4, 2], "wedge": [0, 1, 3, 2, 4, 5], "hexahedron": [0, 1, 3, 4, 2, 7, 5, 6], } meshio_to_flac3d_order_2 = { "tetra": [0, 2, 1, 3], "pyramid": [0, 3, 1, 4, 2], "wedge": [0, 2, 3, 1, 5, 4], "hexahedron": [0, 3, 1, 4, 2, 5, 7, 6], } flag_to_numdim = { "zone": 3, "face": 2, } def _merge(a: dict, b: dict) -> dict: return {**a, **b} def read(filename): """Read FLAC3D f3grid grid file.""" # Read a small block of the file to assess its type # See with open_file(filename, "rb") as f: block = f.read(8) binary = b"\x00" in block mode = "rb" if binary else "r" with open_file(filename, mode) as f: out = read_buffer(f, binary) return out def read_buffer(f, binary): """Read binary or ASCII file.""" points = [] point_ids = {} f_cells = [] z_cells = [] f_cell_sets = {} z_cell_sets = {} f_cell_ids = [] z_cell_ids = [] pidx = 0 if binary: # Not sure what the first bytes represent, the format might be wrong # It does not seem to be useful anyway _ = struct.unpack("<2I", f.read(8)) (num_nodes,) = struct.unpack(" 0: f_inv = np.full(np.max(f_cell_ids) + 1, -1) f_inv[f_cell_ids] = np.arange(len(f_cell_ids)) f_cell_sets = {key: f_inv[value] for key, value in f_cell_sets.items()} if len(z_cell_ids) > 0: z_inv = np.full(np.max(z_cell_ids) + 1, -1) z_inv[z_cell_ids] = np.arange(len(z_cell_ids)) z_cell_sets = { key: z_inv[value] + z_offset for key, value in z_cell_sets.items() } cell_sets = _merge(f_cell_sets, z_cell_sets) # cell_sets contains the indices into the global cell list. Since this is # split up into blocks, we need to split the cell_sets, too. bins = np.cumsum([len(cb[1]) for cb in cell_blocks]) for key, data in cell_sets.items(): d = np.digitize(data, bins) cell_sets[key] = [data[d == k] for k in range(len(cell_blocks))] # assert len(cell_ids) == sum(len(block) for _, block in cell_blocks) # also store the cell_ids cell_data = {} if len(cell_blocks) > 0: cell_data = { "cell_ids": np.split( cell_ids, np.cumsum([len(block) for _, block in cell_blocks][:-1]) ) } return Mesh( points=np.array(points), cells=cell_blocks, cell_data=cell_data, cell_sets=cell_sets, ) def _read_point_ascii(buf_or_line): """Read point coordinates.""" pid = int(buf_or_line[1]) point = [float(l) for l in buf_or_line[2:]] return pid, point def _read_point_binary(buf_or_line): """Read point coordinates.""" pid, x, y, z = struct.unpack(" 0 and cell_type == cells[-1][0]: cells[-1][1].append(cell) else: cells.append((cell_type, [cell])) def split_f_z(mesh): # FLAC3D makes a difference between ZONES (3D-cells only) and FACES # (2D-cells only). Split cells into zcells and fcells, along with the cell # sets etc. zcells = [] fcells = [] for cell_block in mesh.cells: if cell_block.type in meshio_only["zone"]: zcells.append(cell_block) elif cell_block.type in meshio_only["face"]: fcells.append(cell_block) zsets = {} fsets = {} for key, cset in mesh.cell_sets.items(): zsets[key] = [] fsets[key] = [] for cell_block, sblock in zip(mesh.cells, cset): zsets[key].append( sblock if cell_block.type in meshio_only["zone"] else None ) fsets[key].append( sblock if cell_block.type in meshio_only["face"] else None ) # remove the data that is only None zsets = { key: value for key, value in zsets.items() if not all(item is None for item in value) } fsets = { key: value for key, value in fsets.items() if not all(item is None for item in value) } # Right now, the zsets contain indices into the corresponding cell block. # FLAC3D expects _global_ indices. Update. cell_block_sizes = [len(cb) for cb in zcells] for key, data in zsets.items(): gid = 0 for n, block in zip(cell_block_sizes, data): block += gid gid += n # TODO not sure if fcells and zcells share a common global index cell_block_sizes = [len(cb) for cb in fcells] for key, data in fsets.items(): gid = 0 for n, block in zip(cell_block_sizes, data): block += gid gid += n for label, values in zsets.items(): zsets[label] = np.concatenate(values) for label, values in fsets.items(): fsets[label] = np.concatenate(values) # flac3d indices start at 1 for label, values in zsets.items(): zsets[label] += 1 for label, values in fsets.items(): fsets[label] += 1 return zcells, fcells, zsets, fsets def write(filename, mesh: Mesh, float_fmt: str = ".16e", binary: bool = False): """Write FLAC3D f3grid grid file.""" skip = [c.type for c in mesh.cells if c.type not in meshio_only["zone"]] if skip: warn(f'FLAC3D format only supports 3D cells. Skipping {", ".join(skip)}.') # split into face/zone data zcells, fcells, zsets, fsets = split_f_z(mesh) mode = "wb" if binary else "w" with open_file(filename, mode) as f: if binary: # Don't know what these values represent f.write(struct.pack("<2I", 1375135718, 3)) else: f.write(f"* FLAC3D grid produced by meshio v{version}\n") f.write(f"* {time.ctime()}\n") _write_points(f, mesh.points, binary, float_fmt) # Make gid an array such that its value can be persitently altered # inside the functions. gid = np.array(0) # cells = _translate_zcells(mesh.points, mesh.cells) _write_cells(f, cells, "zone", binary, gid) _write_groups(f, mesh.cells, zsets, "zone", binary) # cells = _translate_fcells(fcells) _write_cells(f, cells, "face", binary, gid) _write_groups(f, mesh.cells, fsets, "face", binary) def _write_points(f, points, binary, float_fmt=None): """Write points coordinates.""" if binary: f.write(struct.pack(" None: """Write groups.""" if materials is None: if binary: f.write(struct.pack(" def slicing_summing(a, b, c): c0 = b[:, 1] * c[:, 2] - b[:, 2] * c[:, 1] c1 = b[:, 2] * c[:, 0] - b[:, 0] * c[:, 2] c2 = b[:, 0] * c[:, 1] - b[:, 1] * c[:, 0] return a[:, 0] * c0 + a[:, 1] * c1 + a[:, 2] * c2 zones = [] for cell_block in cells: assert cell_block.type in meshio_only["zone"] # Compute scalar triple products key = meshio_only["zone"][cell_block.type] tmp = points[cell_block.data[:, meshio_to_flac3d_order[key][:4]].T] det = slicing_summing(tmp[1] - tmp[0], tmp[2] - tmp[0], tmp[3] - tmp[0]) # Reorder corner points data = np.where( (det > 0)[:, None], cell_block.data[:, meshio_to_flac3d_order[key]], cell_block.data[:, meshio_to_flac3d_order_2[key]], ) zones.append((key, data)) return zones def _translate_fcells(cells): """Reorder meshio cells to FLAC3D faces.""" faces = [] for cell_block in cells: ctype, data = cell_block assert ctype in meshio_only["face"] key = meshio_only["face"][ctype] data = cell_block.data[:, meshio_to_flac3d_order[key]] faces.append((key, data)) return faces def _translate_groups(cells, cell_data, field_data, flag): """Convert meshio cell_data to FLAC3D groups.""" dim = np.concatenate( [np.full(len(c.data), 2 if c.type in meshio_only["face"] else 3) for c in cells] ) numdim = flag_to_numdim[flag] groups = { k: np.nonzero(np.logical_and(cell_data == k, dim == numdim))[0] + 1 for k in np.unique(cell_data) } groups = {k: v for k, v in groups.items() if v.size} labels = {k: str(k) for k in groups.keys()} labels[0] = "None" if field_data: labels.update( {v[0]: k for k, v in field_data.items() if v[1] == flag_to_numdim[flag]} ) return dict(zip(labels.values(), groups.values())) def _write_table(f, data, ncol: int = 20): """Write group data table.""" nrow = len(data) // ncol lines = np.split(data, np.full(nrow, ncol).cumsum()) for line in lines: if len(line): f.write(" {}\n".format(" ".join([str(l) for l in line]))) register_format("flac3d", [".f3grid"], read, {"flac3d": write}) src/meshio/gmsh/000077500000000000000000000000001456244072500141005ustar00rootroot00000000000000src/meshio/gmsh/__init__.py000066400000000000000000000003511456244072500162100ustar00rootroot00000000000000from .common import _gmsh_to_meshio_type as gmsh_to_meshio_type from .common import _meshio_to_gmsh_type as meshio_to_gmsh_type from .main import read, write __all__ = ["read", "write", "gmsh_to_meshio_type", "meshio_to_gmsh_type"] src/meshio/gmsh/_gmsh22.py000066400000000000000000000345341456244072500157240ustar00rootroot00000000000000""" I/O for Gmsh's msh format, cf. . """ from __future__ import annotations import numpy as np from .._common import cell_data_from_raw, num_nodes_per_cell, raw_from_cell_data, warn from .._exceptions import ReadError from .._mesh import CellBlock, Mesh from .common import ( _fast_forward_over_blank_lines, _fast_forward_to_end_block, _gmsh_to_meshio_order, _gmsh_to_meshio_type, _meshio_to_gmsh_order, _meshio_to_gmsh_type, _read_data, _read_physical_names, _write_data, _write_physical_names, ) c_int = np.dtype("i") c_double = np.dtype("d") def read_buffer(f, is_ascii, data_size): # The format is specified at # . # Initialize the optional data fields points = [] cells = [] field_data = {} cell_data_raw = {} cell_tags = {} point_data = {} periodic = None point_tags = None has_additional_tag_data = False while True: # fast-forward over blank lines line, is_eof = _fast_forward_over_blank_lines(f) if is_eof: break if line[0] != "$": raise ReadError(f"Unexpected line {repr(line)}") environ = line[1:].strip() if environ == "PhysicalNames": _read_physical_names(f, field_data) elif environ == "Nodes": points, point_tags = _read_nodes(f, is_ascii) elif environ == "Elements": has_additional_tag_data, cell_tags = _read_cells( f, cells, point_tags, is_ascii ) elif environ == "Periodic": periodic = _read_periodic(f) elif environ == "NodeData": _read_data(f, "NodeData", point_data, data_size, is_ascii) elif environ == "ElementData": _read_data(f, "ElementData", cell_data_raw, data_size, is_ascii) else: _fast_forward_to_end_block(f, environ) if has_additional_tag_data: warn("The file contains tag data that couldn't be processed.") cell_data = cell_data_from_raw(cells, cell_data_raw) # merge cell_tags into cell_data for tag_name, tag_dict in cell_tags.items(): if tag_name not in cell_data: cell_data[tag_name] = [] offset = {} for cell_type, cell_array in cells: start = offset.setdefault(cell_type, 0) end = start + len(cell_array) offset[cell_type] = end tags = tag_dict.get(cell_type, []) tags = np.array(tags[start:end], dtype=c_int) cell_data[tag_name].append(tags) return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data, gmsh_periodic=periodic, ) def _read_nodes(f, is_ascii): # The first line is the number of nodes line = f.readline().decode() num_nodes = int(line) if is_ascii: points = np.fromfile(f, count=num_nodes * 4, sep=" ").reshape((num_nodes, 4)) # The first number is the index point_tags = points[:, 0] points = points[:, 1:] else: # binary dtype = [("index", c_int), ("x", c_double, (3,))] data = np.fromfile(f, count=num_nodes, dtype=dtype) if not (data["index"] == range(1, num_nodes + 1)).all(): raise ReadError() points = np.ascontiguousarray(data["x"]) point_tags = data["index"] _fast_forward_to_end_block(f, "Nodes") return points, point_tags def _read_cells(f, cells, point_tags, is_ascii): # The first line is the number of elements line = f.readline().decode() total_num_cells = int(line) has_additional_tag_data = False cell_tags = {} if is_ascii: _read_cells_ascii(f, cells, cell_tags, total_num_cells) else: _read_cells_binary(f, cells, cell_tags, total_num_cells) # override cells in-place cells[:] = [(key, _gmsh_to_meshio_order(key, values)) for key, values in cells] point_tags = np.asarray(point_tags, dtype=np.int32) - 1 remap = -np.ones((np.max(point_tags) + 1,), dtype=np.int32) remap[point_tags] = np.arange(point_tags.shape[0]) for ic, (ct, cd) in enumerate(cells): cells[ic] = (ct, remap[cd]) _fast_forward_to_end_block(f, "Elements") # restrict to the standard two data items (physical, geometrical) output_cell_tags = {} for cell_type in cell_tags: physical = [] geometrical = [] for item in cell_tags[cell_type]: if len(item) > 0: physical.append(item[0]) if len(item) > 1: geometrical.append(item[1]) if len(item) > 2: has_additional_tag_data = True physical = np.array(physical, dtype=c_int) geometrical = np.array(geometrical, dtype=c_int) if len(physical) > 0: if "gmsh:physical" not in output_cell_tags: output_cell_tags["gmsh:physical"] = {} output_cell_tags["gmsh:physical"][cell_type] = physical if len(geometrical) > 0: if "gmsh:geometrical" not in output_cell_tags: output_cell_tags["gmsh:geometrical"] = {} output_cell_tags["gmsh:geometrical"][cell_type] = geometrical return has_additional_tag_data, output_cell_tags def _read_cells_ascii(f, cells, cell_tags, total_num_cells: int) -> None: for _ in range(total_num_cells): line = f.readline().decode() data = [int(k) for k in filter(None, line.split())] t = _gmsh_to_meshio_type[data[1]] num_nodes_per_elem = num_nodes_per_cell[t] if len(cells) == 0 or t != cells[-1][0]: cells.append((t, [])) cells[-1][1].append(data[-num_nodes_per_elem:]) # data[2] gives the number of tags. The gmsh manual # # says: # >>> # By default, the first tag is the number of the physical entity to which the # element belongs; the second is the number of the elementary geometrical entity # to which the element belongs; the third is the number of mesh partitions to # which the element belongs, followed by the partition ids (negative partition # ids indicate ghost cells). A zero tag is equivalent to no tag. Gmsh and most # codes using the MSH 2 format require at least the first two tags (physical and # elementary tags). # <<< num_tags = data[2] if t not in cell_tags: cell_tags[t] = [] cell_tags[t].append(data[3 : 3 + num_tags]) # convert to numpy arrays # Subtract one to account for the fact that python indices are 0-based. for k, c in enumerate(cells): cells[k] = (c[0], np.array(c[1], dtype=c_int) - 1) # Cannot convert cell_tags[key] to numpy array: There may be a different number of # tags for each cell. def _read_cells_binary(f, cells, cell_tags, total_num_cells): num_elems = 0 while num_elems < total_num_cells: # read element header elem_type, num_elems0, num_tags = np.fromfile(f, count=3, dtype=c_int) t = _gmsh_to_meshio_type[elem_type] num_nodes_per_elem = num_nodes_per_cell[t] # read element data shape = (num_elems0, 1 + num_tags + num_nodes_per_elem) count = shape[0] * shape[1] data = np.fromfile(f, count=count, dtype=c_int).reshape(shape) if len(cells) == 0 or t != cells[-1][0]: cells.append((t, [])) cells[-1][1].append(data[:, -num_nodes_per_elem:]) if t not in cell_tags: cell_tags[t] = [] cell_tags[t].append(data[:, 1 : num_tags + 1]) num_elems += num_elems0 # collect cells for k, c in enumerate(cells): cells[k] = (c[0], np.vstack(c[1]) - 1) # collect cell tags for key in cell_tags: cell_tags[key] = np.vstack(cell_tags[key]) def _read_periodic(f): periodic = [] num_periodic = int(f.readline().decode()) for _ in range(num_periodic): line = f.readline().decode() edim, stag, mtag = (int(s) for s in line.split()) line = f.readline().decode().strip() if line.startswith("Affine"): affine = line.replace("Affine", "", 1) affine = np.fromstring(affine, float, sep=" ") num_nodes = int(f.readline().decode()) else: affine = None num_nodes = int(line) slave_master = [] for _ in range(num_nodes): line = f.readline().decode() snode, mnode = (int(s) for s in line.split()) slave_master.append([snode, mnode]) slave_master = np.array(slave_master, dtype=c_int).reshape(-1, 2) slave_master -= 1 # Subtract one, Python is 0-based periodic.append([edim, (stag, mtag), affine, slave_master]) _fast_forward_to_end_block(f, "Periodic") return periodic def write(filename, mesh, float_fmt=".16e", binary=True): """Writes msh files, cf. . """ # Filter the point data: gmsh:dim_tags are tags, the rest is actual point data. point_data = {} for key, d in mesh.point_data.items(): if key not in ["gmsh:dim_tags"]: point_data[key] = d # Split the cell data: gmsh:physical and gmsh:geometrical are tags, the rest is # actual cell data. tag_data = {} cell_data = {} for key, d in mesh.cell_data.items(): if key in ["gmsh:physical", "gmsh:geometrical", "cell_tags"]: tag_data[key] = d else: cell_data[key] = d # Always include the physical and geometrical tags. See also the quoted excerpt from # the gmsh documentation in the _read_cells_ascii function above. for tag in ["gmsh:physical", "gmsh:geometrical"]: if tag not in tag_data: warn(f"Appending zeros to replace the missing {tag[5:]} tag data.") tag_data[tag] = [ np.zeros(len(cell_block), dtype=c_int) for cell_block in mesh.cells ] with open(filename, "wb") as fh: mode_idx = 1 if binary else 0 size_of_double = 8 fh.write(f"$MeshFormat\n2.2 {mode_idx} {size_of_double}\n".encode()) if binary: np.array([1], dtype=c_int).tofile(fh) fh.write(b"\n") fh.write(b"$EndMeshFormat\n") if mesh.field_data: _write_physical_names(fh, mesh.field_data) _write_nodes(fh, mesh.points, float_fmt, binary) _write_elements(fh, mesh.cells, tag_data, binary) if mesh.gmsh_periodic is not None: _write_periodic(fh, mesh.gmsh_periodic, float_fmt) for name, dat in point_data.items(): _write_data(fh, "NodeData", name, dat, binary) cell_data_raw = raw_from_cell_data(cell_data) for name, dat in cell_data_raw.items(): _write_data(fh, "ElementData", name, dat, binary) def _write_nodes(fh, points, float_fmt, binary): if points.shape[1] == 2: # msh2 requires 3D points, but 2D points given. Appending 0 third component. points = np.column_stack([points, np.zeros_like(points[:, 0])]) fh.write(b"$Nodes\n") fh.write(f"{len(points)}\n".encode()) if binary: dtype = [("index", c_int), ("x", c_double, (3,))] tmp = np.empty(len(points), dtype=dtype) tmp["index"] = 1 + np.arange(len(points)) tmp["x"] = points tmp.tofile(fh) fh.write(b"\n") else: fmt = "{} " + " ".join(3 * ["{:" + float_fmt + "}"]) + "\n" for k, x in enumerate(points): fh.write(fmt.format(k + 1, x[0], x[1], x[2]).encode()) fh.write(b"$EndNodes\n") def _write_elements(fh, cells: list[CellBlock], tag_data, binary: bool): # write elements fh.write(b"$Elements\n") # count all cells total_num_cells = sum(len(cell_block) for cell_block in cells) fh.write(f"{total_num_cells}\n".encode()) consecutive_index = 0 for k, cell_block in enumerate(cells): cell_type = cell_block.type node_idcs = _meshio_to_gmsh_order(cell_type, cell_block.data) tags = [] for name in ["gmsh:physical", "gmsh:geometrical", "cell_tags"]: if name in tag_data: tags.append(tag_data[name][k]) fcd = np.concatenate([tags]).astype(c_int).T if len(fcd) == 0: fcd = np.empty((len(node_idcs), 0), dtype=c_int) if binary: # header header = [_meshio_to_gmsh_type[cell_type], node_idcs.shape[0], fcd.shape[1]] np.array(header, dtype=c_int).tofile(fh) # actual data a = np.arange(len(node_idcs), dtype=c_int)[:, np.newaxis] a += 1 + consecutive_index array = np.hstack([a, fcd, node_idcs + 1]) if array.dtype != c_int: array = array.astype(c_int) array.tofile(fh) else: form = ( "{} " + str(_meshio_to_gmsh_type[cell_type]) + " " + str(fcd.shape[1]) + " {} {}\n" ) for i, c in enumerate(node_idcs): fh.write( form.format( consecutive_index + i + 1, " ".join([str(val) for val in fcd[i]]), # a bit clumsy for `c+1`, but if c is uint64, c+1 is float64 " ".join([str(cc) for cc in c + np.array(1, dtype=c.dtype)]), ).encode() ) consecutive_index += len(node_idcs) if binary: fh.write(b"\n") fh.write(b"$EndElements\n") def _write_periodic(fh, periodic, float_fmt): fh.write(b"$Periodic\n") fh.write(f"{len(periodic)}\n".encode()) for dim, (stag, mtag), affine, slave_master in periodic: fh.write(f"{dim} {stag} {mtag}\n".encode()) if affine is not None: fh.write(b"Affine ") affine = np.array(affine, dtype=float) affine = np.atleast_2d(affine.ravel()) np.savetxt(fh, affine, fmt="%" + float_fmt) slave_master = np.array(slave_master, dtype=c_int).reshape(-1, 2) slave_master = slave_master + 1 # Add one, Gmsh is 0-based fh.write(f"{len(slave_master)}\n".encode()) for snode, mnode in slave_master: fh.write(f"{snode} {mnode}\n".encode()) fh.write(b"$EndPeriodic\n") src/meshio/gmsh/_gmsh40.py000066400000000000000000000345041456244072500157210ustar00rootroot00000000000000""" I/O for Gmsh's msh format (version 4.0, as used by Gmsh 4.1.5), cf. . """ from __future__ import annotations from functools import partial import numpy as np from .._common import cell_data_from_raw, num_nodes_per_cell, raw_from_cell_data from .._exceptions import ReadError from .._mesh import CellBlock, Mesh from .common import ( _fast_forward_to_end_block, _gmsh_to_meshio_order, _gmsh_to_meshio_type, _meshio_to_gmsh_order, _meshio_to_gmsh_type, _read_data, _read_physical_names, _write_data, _write_physical_names, ) c_int = np.dtype("i") c_long = np.dtype("l") c_ulong = np.dtype("L") c_double = np.dtype("d") def read_buffer(f, is_ascii: bool, data_size) -> Mesh: # Initialize the optional data fields points = [] field_data = {} cell_data_raw = {} cell_tags = {} point_data = {} physical_tags = None periodic = None while True: line = f.readline().decode() if not line: # EOF break if line[0] != "$": raise ReadError environ = line[1:].strip() if environ == "PhysicalNames": _read_physical_names(f, field_data) elif environ == "Entities": physical_tags = _read_entities(f, is_ascii) elif environ == "Nodes": points, point_tags = _read_nodes(f, is_ascii) elif environ == "Elements": cells, cell_tags = _read_elements(f, point_tags, physical_tags, is_ascii) elif environ == "Periodic": periodic = _read_periodic(f, is_ascii) elif environ == "NodeData": _read_data(f, "NodeData", point_data, data_size, is_ascii) elif environ == "ElementData": _read_data(f, "ElementData", cell_data_raw, data_size, is_ascii) else: # From # : # ``` # Any section with an unrecognized header is simply ignored: you can thus # add comments in a .msh file by putting them e.g. inside a # $Comments/$EndComments section. # ``` # skip environment _fast_forward_to_end_block(f, environ) cell_data = cell_data_from_raw(cells, cell_data_raw) cell_data.update(cell_tags) return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data, gmsh_periodic=periodic, ) def _read_entities(f, is_ascii: bool): physical_tags = tuple({} for _ in range(4)) # dims 0, 1, 2, 3 fromfile = partial(np.fromfile, sep=" " if is_ascii else "") number = fromfile(f, c_ulong, 4) # dims 0, 1, 2, 3 for d, n in enumerate(number): for _ in range(n): tag = int(fromfile(f, c_int, 1)[0]) fromfile(f, c_double, 6) # discard boxMinX...boxMaxZ num_physicals = int(fromfile(f, c_ulong, 1)[0]) physical_tags[d][tag] = list(fromfile(f, c_int, num_physicals)) if d > 0: # discard tagBREP{Vert,Curve,Surfaces} num_BREP = int(fromfile(f, c_ulong, 1)[0]) fromfile(f, c_int, num_BREP) _fast_forward_to_end_block(f, "Entities") return physical_tags def _read_nodes(f, is_ascii): if is_ascii: # first line: numEntityBlocks(unsigned long) numNodes(unsigned long) line = f.readline().decode() num_entity_blocks, total_num_nodes = (int(k) for k in line.split()) points = np.empty((total_num_nodes, 3), dtype=float) tags = np.empty(total_num_nodes, dtype=int) idx = 0 for _ in range(num_entity_blocks): # first line in the entity block: # tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long) line = f.readline().decode() _, _, _, num_nodes = map(int, line.split()) for _ in range(num_nodes): # tag(int) x(double) y(double) z(double) line = f.readline().decode() tag, x, y, z = line.split() points[idx] = [float(x), float(y), float(z)] tags[idx] = tag idx += 1 else: # numEntityBlocks(unsigned long) numNodes(unsigned long) num_entity_blocks, _ = np.fromfile(f, count=2, dtype=c_ulong) points = [] tags = [] for _ in range(num_entity_blocks): # tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long) np.fromfile(f, count=3, dtype=c_int) num_nodes = np.fromfile(f, count=1, dtype=c_ulong)[0] dtype = [("tag", c_int), ("x", c_double, (3,))] data = np.fromfile(f, count=num_nodes, dtype=dtype) tags.append(data["tag"]) points.append(data["x"]) tags = np.concatenate(tags) points = np.concatenate(points) line = f.readline().decode() if line != "\n": raise ReadError() _fast_forward_to_end_block(f, "Nodes") return points, tags def _read_elements(f, point_tags, physical_tags, is_ascii): fromfile = partial(np.fromfile, sep=" " if is_ascii else "") # numEntityBlocks(unsigned long) numElements(unsigned long) num_entity_blocks, _ = fromfile(f, c_ulong, 2) data = [] for _ in range(num_entity_blocks): # tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long) tag_entity, dim_entity, type_ele = fromfile(f, c_int, 3) (num_ele,) = fromfile(f, c_ulong, 1) tpe = _gmsh_to_meshio_type[type_ele] num_nodes_per_ele = num_nodes_per_cell[tpe] d = fromfile(f, c_int, int(num_ele * (1 + num_nodes_per_ele))).reshape( (num_ele, -1) ) if physical_tags is None: data.append((None, tag_entity, tpe, d)) else: data.append((physical_tags[dim_entity][tag_entity], tag_entity, tpe, d)) _fast_forward_to_end_block(f, "Elements") # The msh4 elements array refers to the nodes by their tag, not the index. All other # mesh formats use the index, which is far more efficient, too. Hence, # unfortunately, we have to do a fairly expensive conversion here. m = np.max(point_tags + 1) itags = -np.ones(m, dtype=int) itags[point_tags] = np.arange(len(point_tags)) # Note that the first column in the data array is the element tag; discard it. data = [ (physical_tag, geom_tag, tpe, itags[d[:, 1:]]) for physical_tag, geom_tag, tpe, d in data ] cells = [] cell_data = {} for physical_tag, geom_tag, key, values in data: cells.append(CellBlock(key, _gmsh_to_meshio_order(key, values))) if physical_tag: if "gmsh:physical" not in cell_data: cell_data["gmsh:physical"] = [] cell_data["gmsh:physical"].append( np.full(len(values), physical_tag[0], int) ) if "gmsh:geometrical" not in cell_data: cell_data["gmsh:geometrical"] = [] cell_data["gmsh:geometrical"].append(np.full(len(values), geom_tag, int)) return cells, cell_data def _read_periodic(f, is_ascii): fromfile = partial(np.fromfile, sep=" " if is_ascii else "") periodic = [] num_periodic = int(fromfile(f, c_int, 1)[0]) for _ in range(num_periodic): edim, stag, mtag = fromfile(f, c_int, 3) if is_ascii: line = f.readline().decode().strip() if line.startswith("Affine"): affine = line.replace("Affine", "", 1) affine = np.fromstring(affine, float, sep=" ") num_nodes = int(f.readline().decode()) else: affine = None num_nodes = int(line) else: num_nodes = int(fromfile(f, c_long, 1)[0]) if num_nodes < 0: affine = fromfile(f, c_double, 16) num_nodes = int(fromfile(f, c_ulong, 1)[0]) else: affine = None slave_master = fromfile(f, c_int, num_nodes * 2).reshape(-1, 2) slave_master = slave_master - 1 # Subtract one, Python is 0-based periodic.append([edim, (stag, mtag), affine, slave_master]) _fast_forward_to_end_block(f, "Periodic") return periodic def write(filename, mesh: Mesh, float_fmt: str = ".16e", binary: bool = True) -> None: """Writes msh files, cf. . """ with open(filename, "wb") as fh: mode_idx = 1 if binary else 0 size_of_double = 8 fh.write(f"$MeshFormat\n4.0 {mode_idx} {size_of_double}\n".encode()) if binary: np.array([1], dtype=c_int).tofile(fh) fh.write(b"\n") fh.write(b"$EndMeshFormat\n") if mesh.field_data: _write_physical_names(fh, mesh.field_data) _write_nodes(fh, mesh.points, float_fmt, binary) _write_elements(fh, mesh.cells, binary) if mesh.gmsh_periodic is not None: _write_periodic(fh, mesh.gmsh_periodic, float_fmt, binary) for name, dat in mesh.point_data.items(): _write_data(fh, "NodeData", name, dat, binary) cell_data_raw = raw_from_cell_data(mesh.cell_data) for name, dat in cell_data_raw.items(): _write_data(fh, "ElementData", name, dat, binary) def _write_nodes(fh, points: np.ndarray, float_fmt: str, binary: bool) -> None: if points.shape[1] == 2: points = np.column_stack([points, np.zeros_like(points[:, 0])]) fh.write(b"$Nodes\n") # TODO not sure what dimEntity is supposed to say dim_entity = 0 type_node = 0 if binary: # write all points as one big block # numEntityBlocks(unsigned long) numNodes(unsigned long) # tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long) # tag(int) x(double) y(double) z(double) np.array([1, points.shape[0]], dtype=c_ulong).tofile(fh) np.array([1, dim_entity, type_node], dtype=c_int).tofile(fh) np.array([points.shape[0]], dtype=c_ulong).tofile(fh) dtype = [("index", c_int), ("x", c_double, (3,))] tmp = np.empty(len(points), dtype=dtype) tmp["index"] = 1 + np.arange(len(points)) tmp["x"] = points tmp.tofile(fh) fh.write(b"\n") else: # write all points as one big block # numEntityBlocks(unsigned long) numNodes(unsigned long) fh.write(f"{1} {len(points)}\n".encode()) # tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long) fh.write(f"{1} {dim_entity} {type_node} {len(points)}\n".encode()) fmt = "{} " + " ".join(3 * ["{:" + float_fmt + "}"]) + "\n" for k, x in enumerate(points): # tag(int) x(double) y(double) z(double) fh.write(fmt.format(k + 1, x[0], x[1], x[2]).encode()) fh.write(b"$EndNodes\n") def _write_elements(fh, cell_blocks: list[CellBlock], binary: bool): # TODO respect binary # write elements fh.write(b"$Elements\n") if binary: total_num_cells = sum(len(cell_block) for cell_block in cell_blocks) np.array([len(cell_blocks), total_num_cells], dtype=c_ulong).tofile(fh) consecutive_index = 0 for cell_block in cell_blocks: node_idcs = _meshio_to_gmsh_order(cell_block.type, cell_block.data) # tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long) np.array( [1, cell_block.dim, _meshio_to_gmsh_type[cell_block.type]], dtype=c_int, ).tofile(fh) np.array([node_idcs.shape[0]], dtype=c_ulong).tofile(fh) if node_idcs.dtype != c_int: # Binary Gmsh needs c_int (typically np.int32) integers Converting. node_idcs = node_idcs.astype(c_int) data = np.column_stack( [ np.arange( consecutive_index, consecutive_index + len(node_idcs), dtype=c_int, ), # increment indices by one to conform with gmsh standard node_idcs + 1, ] ) data.tofile(fh) consecutive_index += len(node_idcs) fh.write(b"\n") else: # count all cells total_num_cells = sum(len(cell_block) for cell_block in cell_blocks) fh.write(f"{len(cell_blocks)} {total_num_cells}\n".encode()) consecutive_index = 0 for cell_block in cell_blocks: cell_type = cell_block.type cell_data = _meshio_to_gmsh_order(cell_block.type, cell_block.data) # tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long) fh.write( "{} {} {} {}\n".format( 1, # tag cell_block.dim, _meshio_to_gmsh_type[cell_type], len(cell_data), ).encode() ) # increment indices by one to conform with gmsh standard idcs = cell_data + 1 fmt = " ".join(["{}"] * (num_nodes_per_cell[cell_type] + 1)) + "\n" for idx in idcs: fh.write(fmt.format(consecutive_index, *idx).encode()) consecutive_index += 1 fh.write(b"$EndElements\n") def _write_periodic(fh, periodic, float_fmt, binary): def tofile(fh, value, dtype, **kwargs): ary = np.array(value, dtype=dtype) if binary: ary.tofile(fh) else: ary = np.atleast_2d(ary) fmt = float_fmt if dtype == c_double else "d" fmt = "%" + kwargs.pop("fmt", fmt) np.savetxt(fh, ary, fmt=fmt, **kwargs) fh.write(b"$Periodic\n") tofile(fh, len(periodic), c_int) for dim, (stag, mtag), affine, slave_master in periodic: tofile(fh, [dim, stag, mtag], c_int) if affine is not None and len(affine) > 0: tofile(fh, -1, c_long) tofile(fh, affine, c_double, fmt=float_fmt) slave_master = np.array(slave_master, dtype=c_int) slave_master = slave_master.reshape(-1, 2) slave_master = slave_master + 1 # Add one, Gmsh is 1-based tofile(fh, len(slave_master), c_int) tofile(fh, slave_master, c_int) if binary: fh.write(b"\n") fh.write(b"$EndPeriodic\n") src/meshio/gmsh/_gmsh41.py000066400000000000000000000705761456244072500157330ustar00rootroot00000000000000""" I/O for Gmsh's msh format (version 4.1, as used by Gmsh 4.2.2+), cf. . """ from functools import partial import numpy as np from .._common import cell_data_from_raw, num_nodes_per_cell, raw_from_cell_data, warn from .._exceptions import ReadError, WriteError from .._mesh import CellBlock, Mesh from .common import ( _fast_forward_over_blank_lines, _fast_forward_to_end_block, _gmsh_to_meshio_order, _gmsh_to_meshio_type, _meshio_to_gmsh_order, _meshio_to_gmsh_type, _read_data, _read_physical_names, _write_data, _write_physical_names, ) c_int = np.dtype("i") c_size_t = np.dtype("P") c_double = np.dtype("d") def _size_type(data_size): return np.dtype(f"u{data_size}") def read_buffer(f, is_ascii: bool, data_size): # The format is specified at # . # Initialize the optional data fields points = [] cells = None field_data = {} cell_data_raw = {} cell_tags = {} point_data = {} physical_tags = None bounding_entities = None cell_sets = {} periodic = None while True: # fast-forward over blank lines line, is_eof = _fast_forward_over_blank_lines(f) if is_eof: break if line[0] != "$": raise ReadError(f"Unexpected line {repr(line)}") environ = line[1:].strip() if environ == "PhysicalNames": _read_physical_names(f, field_data) elif environ == "Entities": # Read physical tags and information on bounding entities. # The information is passed to the processing of elements. physical_tags, bounding_entities = _read_entities(f, is_ascii, data_size) elif environ == "Nodes": points, point_tags, point_entities = _read_nodes(f, is_ascii, data_size) elif environ == "Elements": cells, cell_tags, cell_sets = _read_elements( f, point_tags, physical_tags, bounding_entities, is_ascii, data_size, field_data, ) elif environ == "Periodic": periodic = _read_periodic(f, is_ascii, data_size) elif environ == "NodeData": _read_data(f, "NodeData", point_data, data_size, is_ascii) elif environ == "ElementData": _read_data(f, "ElementData", cell_data_raw, data_size, is_ascii) else: # From # : # ``` # Any section with an unrecognized header is simply ignored: you can thus # add comments in a .msh file by putting them e.g. inside a # $Comments/$EndComments section. # ``` # skip environment _fast_forward_to_end_block(f, environ) if cells is None: raise ReadError("$Element section not found.") cell_data = cell_data_from_raw(cells, cell_data_raw) cell_data.update(cell_tags) # Add node entity information to the point data point_data.update({"gmsh:dim_tags": point_entities}) return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data, cell_sets=cell_sets, gmsh_periodic=periodic, ) def _read_entities(f, is_ascii: bool, data_size): # Read the entity section. Return physical tags of the entities, and (for # entities of dimension > 0) the bounding entities (so points that form # the boundary of a line etc). # Note that the bounding box of the entities is disregarded. Adding this # is not difficult, but for the moment, the entropy of adding more data # does not seem warranted. fromfile = partial(np.fromfile, sep=" " if is_ascii else "") c_size_t = _size_type(data_size) physical_tags = ({}, {}, {}, {}) bounding_entities = ({}, {}, {}, {}) number = fromfile(f, c_size_t, 4) # dims 0, 1, 2, 3 for d, n in enumerate(number): for _ in range(n): (tag,) = fromfile(f, c_int, 1) fromfile(f, c_double, 3 if d == 0 else 6) # discard bounding-box (num_physicals,) = fromfile(f, c_size_t, 1) physical_tags[d][tag] = list(fromfile(f, c_int, num_physicals)) if d > 0: # Number of bounding entities num_BREP_ = fromfile(f, c_size_t, 1)[0] # Store bounding entities bounding_entities[d][tag] = fromfile(f, c_int, num_BREP_) _fast_forward_to_end_block(f, "Entities") return physical_tags, bounding_entities def _read_nodes(f, is_ascii: bool, data_size): # Read node data: Node coordinates and tags. # Also find the entities of the nodes, and store this as point_data. # Note that entity tags are 1-offset within each dimension, thus it is # necessary to keep track of both tag and dimension of the entity fromfile = partial(np.fromfile, sep=" " if is_ascii else "") c_size_t = _size_type(data_size) # numEntityBlocks numNodes minNodeTag maxNodeTag (all size_t) num_entity_blocks, total_num_nodes, _, _ = fromfile(f, c_size_t, 4) points = np.empty((total_num_nodes, 3), dtype=float) tags = np.empty(total_num_nodes, dtype=int) dim_tags = np.empty((total_num_nodes, 2), dtype=int) # To save the entity block id for each node, initialize an array here, # populate it with num_nodes idx = 0 for _ in range(num_entity_blocks): # entityDim(int) entityTag(int) parametric(int) numNodes(size_t) dim, entity_tag, parametric = fromfile(f, c_int, 3) if parametric != 0: raise ReadError("parametric nodes not implemented") num_nodes = int(fromfile(f, c_size_t, 1)[0]) # From : # > [...] tags can be "sparse", i.e., do not have to constitute a continuous # > list of numbers (the format even allows them to not be ordered). # # Following https://github.com/nschloe/meshio/issues/388, we read the tags and # populate the points array accordingly, thereby preserving the order of indices # of nodes/points. ixx = slice(idx, idx + num_nodes) tags[ixx] = fromfile(f, c_size_t, num_nodes) - 1 # Store the point densely and in the order in which they appear in the file. # x(double) y(double) z(double) (* numNodes) points[ixx] = fromfile(f, c_double, num_nodes * 3).reshape((num_nodes, 3)) # Entity tag and entity dimension of the nodes. Stored as point-data. dim_tags[ixx, 0] = dim dim_tags[ixx, 1] = entity_tag idx += num_nodes _fast_forward_to_end_block(f, "Nodes") return points, tags, dim_tags def _read_elements( f, point_tags, physical_tags, bounding_entities, is_ascii, data_size, field_data ): fromfile = partial(np.fromfile, sep=" " if is_ascii else "") c_size_t = _size_type(data_size) # numEntityBlocks numElements minElementTag maxElementTag (all size_t) num_entity_blocks, _, _, _ = fromfile(f, c_size_t, 4) data = [] cell_data = {} cell_sets = {k: [None] * num_entity_blocks for k in field_data.keys()} for k in range(num_entity_blocks): # entityDim(int) entityTag(int) elementType(int) numElements(size_t) dim, tag, type_ele = fromfile(f, c_int, 3) (num_ele,) = fromfile(f, c_size_t, 1) for physical_name, cell_set in cell_sets.items(): cell_set[k] = np.arange( ( num_ele if ( physical_tags and field_data[physical_name][1] == dim and field_data[physical_name][0] in physical_tags[dim][tag] ) else 0 ), dtype=type(num_ele), ) tpe = _gmsh_to_meshio_type[type_ele] num_nodes_per_ele = num_nodes_per_cell[tpe] d = fromfile(f, c_size_t, int(num_ele * (1 + num_nodes_per_ele))).reshape( (num_ele, -1) ) # Find physical tag, if defined; else it is None. pt = None if not physical_tags else physical_tags[dim][tag] # Bounding entities (of lower dimension) if defined. Else it is None. if dim > 0 and bounding_entities: # Points have no boundaries be = bounding_entities[dim][tag] else: be = None data.append((pt, be, tag, tpe, d)) _fast_forward_to_end_block(f, "Elements") # Inverse point tags inv_tags = np.full(np.max(point_tags) + 1, -1, dtype=int) inv_tags[point_tags] = np.arange(len(point_tags)) # Note that the first column in the data array is the element tag; discard it. data = [ (physical_tag, bound_entity, geom_tag, tpe, inv_tags[d[:, 1:] - 1]) for physical_tag, bound_entity, geom_tag, tpe, d in data ] cells = [] for physical_tag, bound_entity, geom_tag, key, values in data: cells.append(CellBlock(key, _gmsh_to_meshio_order(key, values))) if physical_tag: if "gmsh:physical" not in cell_data: cell_data["gmsh:physical"] = [] cell_data["gmsh:physical"].append( np.full(len(values), physical_tag[0], int) ) if "gmsh:geometrical" not in cell_data: cell_data["gmsh:geometrical"] = [] cell_data["gmsh:geometrical"].append(np.full(len(values), geom_tag, int)) # The bounding entities is stored in the cell_sets. if bounding_entities: if "gmsh:bounding_entities" not in cell_sets: cell_sets["gmsh:bounding_entities"] = [] cell_sets["gmsh:bounding_entities"].append(bound_entity) return cells, cell_data, cell_sets def _read_periodic(f, is_ascii, data_size): fromfile = partial(np.fromfile, sep=" " if is_ascii else "") c_size_t = _size_type(data_size) periodic = [] # numPeriodicLinks(size_t) num_periodic = int(fromfile(f, c_size_t, 1)[0]) for _ in range(num_periodic): # entityDim(int) entityTag(int) entityTagMaster(int) edim, stag, mtag = fromfile(f, c_int, 3) # numAffine(size_t) value(double) ... num_affine = int(fromfile(f, c_size_t, 1)[0]) affine = fromfile(f, c_double, num_affine) # numCorrespondingNodes(size_t) num_nodes = int(fromfile(f, c_size_t, 1)[0]) # nodeTag(size_t) nodeTagMaster(size_t) ... slave_master = fromfile(f, c_size_t, num_nodes * 2).reshape(-1, 2) slave_master = slave_master - 1 # Subtract one, Python is 0-based periodic.append([edim, (stag, mtag), affine, slave_master]) _fast_forward_to_end_block(f, "Periodic") return periodic def write(filename, mesh, float_fmt=".16e", binary=True): """Writes msh files, cf. . """ # Filter the point data: gmsh:dim_tags are tags, the rest is actual point data. point_data = {} for key, d in mesh.point_data.items(): if key not in ["gmsh:dim_tags"]: point_data[key] = d # Split the cell data: gmsh:physical and gmsh:geometrical are tags, the rest is # actual cell data. tag_data = {} cell_data = {} for key, d in mesh.cell_data.items(): if key in ["gmsh:physical", "gmsh:geometrical", "cell_tags"]: tag_data[key] = d else: cell_data[key] = d with open(filename, "wb") as fh: file_type = 1 if binary else 0 data_size = c_size_t.itemsize fh.write(b"$MeshFormat\n") fh.write(f"4.1 {file_type} {data_size}\n".encode()) if binary: np.array([1], dtype=c_int).tofile(fh) fh.write(b"\n") fh.write(b"$EndMeshFormat\n") if mesh.field_data: _write_physical_names(fh, mesh.field_data) _write_entities( fh, mesh.cells, tag_data, mesh.cell_sets, mesh.point_data, binary ) _write_nodes(fh, mesh.points, mesh.cells, mesh.point_data, float_fmt, binary) _write_elements(fh, mesh.cells, tag_data, binary) if mesh.gmsh_periodic is not None: _write_periodic(fh, mesh.gmsh_periodic, float_fmt, binary) for name, dat in point_data.items(): _write_data(fh, "NodeData", name, dat, binary) cell_data_raw = raw_from_cell_data(cell_data) for name, dat in cell_data_raw.items(): _write_data(fh, "ElementData", name, dat, binary) def _write_entities(fh, cells, tag_data, cell_sets, point_data, binary): """Write entity section in a .msh file. The entity section links up to three kinds of information: 1) The geometric objects represented in the mesh. 2) Physical tags of geometric objects. This data will be a subset of that represented in 1) 3) Which geometric objects form the boundary of this object. The boundary is formed of objects with dimension 1 less than the current one. A boundary can only be specified for objects of dimension at least 1. The entities of all geometric objects is pulled from point_data['gmsh:dim_tags']. For details, see the function _write_nodes(). Physical tags are specified as tag_data, while the boundary of a geometric object is specified in cell_sets. """ # The data format for the entities section is # # numPoints(size_t) numCurves(size_t) # numSurfaces(size_t) numVolumes(size_t) # pointTag(int) X(double) Y(double) Z(double) # numPhysicalTags(size_t) physicalTag(int) ... # ... # curveTag(int) minX(double) minY(double) minZ(double) # maxX(double) maxY(double) maxZ(double) # numPhysicalTags(size_t) physicalTag(int) ... # numBoundingPoints(size_t) pointTag(int) ... # ... # surfaceTag(int) minX(double) minY(double) minZ(double) # maxX(double) maxY(double) maxZ(double) # numPhysicalTags(size_t) physicalTag(int) ... # numBoundingCurves(size_t) curveTag(int) ... # ... # volumeTag(int) minX(double) minY(double) minZ(double) # maxX(double) maxY(double) maxZ(double) # numPhysicalTags(size_t) physicalTag(int) ... # numBoundngSurfaces(size_t) surfaceTag(int) ... # Both nodes and cells have entities, but the cell entities are a subset of # the nodes. The reason is (if the inner workings of Gmsh has been correctly # understood) that node entities are assigned to all # objects necessary to specify the geometry whereas only cells of Physical # objcets (gmsh jargon) are present among the cell entities. # The entities section must therefore be built on the node-entities, if # these are available. If this is not the case, we leave this section blank. # TODO: Should this give a warning? if "gmsh:dim_tags" not in point_data: return fh.write(b"$Entities\n") # Array of entity tag (first row) and dimension (second row) per node. # We need to combine the two, since entity tags are reset for each dimension. # Uniquify, so that each row in node_dim_tags represent a unique entity node_dim_tags = np.unique(point_data["gmsh:dim_tags"], axis=0) # Write number of entities per dimension num_occ = np.bincount(node_dim_tags[:, 0], minlength=4) if num_occ.size > 4: raise ValueError("Encountered entity with dimension > 3") if binary: num_occ.astype(c_size_t).tofile(fh) else: fh.write(f"{num_occ[0]} {num_occ[1]} {num_occ[2]} {num_occ[3]}\n".encode()) # Array of dimension and entity tag per cell. Will be compared with the # similar not array. cell_dim_tags = np.empty((len(cells), 2), dtype=int) for ci, cell_block in enumerate(cells): cell_dim_tags[ci] = [ cell_block.dim, tag_data["gmsh:geometrical"][ci][0], ] # We will only deal with bounding entities if this information is available has_bounding_elements = "gmsh:bounding_entities" in cell_sets # The node entities form a superset of cell entities. Write entity information # based on nodes, supplement with cell information when there is a matcihng # cell block. for dim, tag in node_dim_tags: # Find the matching cell block, if it exists matching_cell_block = np.where( np.logical_and(cell_dim_tags[:, 0] == dim, cell_dim_tags[:, 1] == tag) )[0] if matching_cell_block.size > 1: # It is not 100% clear if this is not permissible, but the current # implementation for sure does not allow it. raise ValueError("Encountered non-unique CellBlock dim_tag") # The information to be written varies according to entity dimension, # whether entity has a physical tag, and between ascii and binary. # The resulting code is a bit ugly, but no simpler and clean option # seems possible. # Entity tag if binary: np.array([tag], dtype=c_int).tofile(fh) else: fh.write(f"{tag} ".encode()) # Min-max coordinates for the entity. For now, simply put zeros here, # and hope that gmsh does not complain. To expand this, the point # coordinates must be made available to this function; the bounding # box can then be found by a min-max over the points of the matching # cell. if dim == 0: # Bounding box is a point if binary: np.zeros(3, dtype=c_double).tofile(fh) else: fh.write(b"0 0 0 ") else: # Bounding box has six coordinates if binary: np.zeros(6, dtype=c_double).tofile(fh) else: fh.write(b"0 0 0 0 0 0 ") # If there is a corresponding cell block, write physical tags (if any) # and bounding entities (if any) if matching_cell_block.size > 0: # entity has a physical tag, write this # ASSUMPTION: There is a single physical tag for this physical_tag = tag_data["gmsh:physical"][matching_cell_block[0]][0] if binary: np.array([1], dtype=c_size_t).tofile(fh) np.array([physical_tag], dtype=c_int).tofile(fh) else: fh.write(f"1 {physical_tag} ".encode()) else: # The number of physical tags is zero if binary: np.array([0], dtype=c_size_t).tofile(fh) else: fh.write(b"0 ") if dim > 0: # Entities not of the lowest dimension can have their # bounding elements (of dimension one less) specified if has_bounding_elements and matching_cell_block.size > 0: # The bounding element should be a list bounds = cell_sets["gmsh:bounding_entities"][matching_cell_block[0]] num_bounds = len(bounds) if num_bounds > 0: if binary: np.array(num_bounds, dtype=c_size_t).tofile(fh) np.array(bounds, dtype=c_int).tofile(fh) else: fh.write(f"{num_bounds} ".encode()) for bi in bounds: fh.write(f"{bi} ".encode()) fh.write(b"\n") else: # Register that there are no bounding elements if binary: np.array([0], dtype=c_size_t).tofile(fh) else: fh.write(b"0\n") else: # Register that there are no bounding elements if binary: np.array([0], dtype=c_size_t).tofile(fh) else: fh.write(b"0\n") else: # If ascii, enforce line change if not binary: fh.write(b"\n") if binary: fh.write(b"\n") # raise NotImplementedError fh.write(b"$EndEntities\n") def _write_nodes(fh, points, cells, point_data, float_fmt, binary): """Write node information. If data on dimension and tags of the geometric entities which the nodes belong to is available available, the nodes will be grouped accordingly. This data is specified as point_data, using the key 'gmsh:dim_tags' and data as an num_points x 2 numpy array (first column is the dimension of the geometric entity of this node, second is the tag). If dim_tags are not available, all nodes will be assigned the same tag of 0. This only makes sense if a single cell block is present in the mesh; an error will be raised if len(cells) > 1. """ if points.shape[1] == 2: # msh4 requires 3D points, but 2D points given. # Appending 0 third component. points = np.column_stack([points, np.zeros_like(points[:, 0])]) fh.write(b"$Nodes\n") # The format for the nodes section is # # $Nodes # numEntityBlocks(size_t) numNodes(size_t) minNodeTag(size_t) maxNodeTag(size_t) # entityDim(int) entityTag(int) parametric(int; 0 or 1) # numNodesInBlock(size_t) # nodeTag(size_t) # ... # x(double) y(double) z(double) # < u(double; if parametric and entityDim >= 1) > # < v(double; if parametric and entityDim >= 2) > # < w(double; if parametric and entityDim == 3) > # ... # ... # $EndNodes # n = points.shape[0] min_tag = 1 max_tag = n is_parametric = 0 # If node (entity) tag and dimension is available, we make a list of unique # combinations thereof, and a map from the full node set to the unique # set. if "gmsh:dim_tags" in point_data: # reverse_index_map maps from all nodes to their respective representation in # (the uniquified) node_dim_tags. This approach works for general orderings of # the nodes node_dim_tags, reverse_index_map = np.unique( point_data["gmsh:dim_tags"], axis=0, return_inverse=True, ) else: # If entity information is not provided, we will assign the same entity for all # nodes. This only makes sense if the cells are of a single type if len(cells) != 1: raise WriteError( "Specify entity information (gmsh:dim_tags in point_data) " + "to deal with more than one cell type. " ) dim = cells[0].dim tag = 0 node_dim_tags = np.array([[dim, tag]]) # All nodes map to the (single) dimension-entity object reverse_index_map = np.full(n, 0, dtype=int) num_blocks = node_dim_tags.shape[0] # First write preamble if binary: if points.dtype != c_double: warn(f"Binary Gmsh needs c_double points (got {points.dtype}). Converting.") points = points.astype(c_double) np.array([num_blocks, n, min_tag, max_tag], dtype=c_size_t).tofile(fh) else: fh.write(f"{num_blocks} {n} {min_tag} {max_tag}\n".encode()) for j in range(num_blocks): dim, tag = node_dim_tags[j] node_tags = np.where(reverse_index_map == j)[0] num_points_this = node_tags.size if binary: np.array([dim, tag, is_parametric], dtype=c_int).tofile(fh) np.array([num_points_this], dtype=c_size_t).tofile(fh) (node_tags + 1).astype(c_size_t).tofile(fh) points[node_tags].tofile(fh) else: fh.write(f"{dim} {tag} {is_parametric} {num_points_this}\n".encode()) (node_tags + 1).astype(c_size_t).tofile(fh, "\n", "%d") fh.write(b"\n") np.savetxt(fh, points[node_tags], delimiter=" ", fmt="%" + float_fmt) if binary: fh.write(b"\n") fh.write(b"$EndNodes\n") def _write_elements(fh, cells, tag_data, binary: bool) -> None: """write the $Elements block $Elements numEntityBlocks(size_t) numElements(size_t) minElementTag(size_t) maxElementTag(size_t) entityDim(int) entityTag(int) elementType(int; see below) numElementsInBlock(size_t) elementTag(size_t) nodeTag(size_t) ... ... ... $EndElements """ fh.write(b"$Elements\n") total_num_cells = sum(len(c) for c in cells) num_blocks = len(cells) min_element_tag = 1 max_element_tag = total_num_cells if binary: np.array( [num_blocks, total_num_cells, min_element_tag, max_element_tag], dtype=c_size_t, ).tofile(fh) tag0 = 1 for ci, cell_block in enumerate(cells): node_idcs = _meshio_to_gmsh_order(cell_block.type, cell_block.data) if node_idcs.dtype != c_size_t: # Binary Gmsh needs c_size_t. Converting." node_idcs = node_idcs.astype(c_size_t) # entityDim(int) entityTag(int) elementType(int) # numElementsBlock(size_t) # The entity tag should be equal within a CellBlock if "gmsh:geometrical" in tag_data: entity_tag = tag_data["gmsh:geometrical"][ci][0] else: entity_tag = 0 cell_type = _meshio_to_gmsh_type[cell_block.type] np.array([cell_block.dim, entity_tag, cell_type], dtype=c_int).tofile(fh) n = node_idcs.shape[0] np.array([n], dtype=c_size_t).tofile(fh) if node_idcs.dtype != c_size_t: warn( f"Binary Gmsh cells need c_size_t (got {node_idcs.dtype}). " + "Converting." ) node_idcs = node_idcs.astype(c_size_t) np.column_stack( [ np.arange(tag0, tag0 + n, dtype=c_size_t), # increment indices by one to conform with gmsh standard node_idcs + 1, ] ).tofile(fh) tag0 += n fh.write(b"\n") else: fh.write( "{} {} {} {}\n".format( num_blocks, total_num_cells, min_element_tag, max_element_tag ).encode() ) tag0 = 1 for ci, cell_block in enumerate(cells): node_idcs = _meshio_to_gmsh_order(cell_block.type, cell_block.data) # entityDim(int) entityTag(int) elementType(int) numElementsBlock(size_t) # The entity tag should be equal within a CellBlock if "gmsh:geometrical" in tag_data: entity_tag = tag_data["gmsh:geometrical"][ci][0] else: entity_tag = 0 cell_type = _meshio_to_gmsh_type[cell_block.type] n = len(cell_block.data) fh.write(f"{cell_block.dim} {entity_tag} {cell_type} {n}\n".encode()) np.savetxt( fh, # Gmsh indexes from 1 not 0 np.column_stack([np.arange(tag0, tag0 + n), node_idcs + 1]), "%d", " ", ) tag0 += n fh.write(b"$EndElements\n") def _write_periodic(fh, periodic, float_fmt: str, binary: bool) -> None: """write the $Periodic block specified as $Periodic numPeriodicLinks(size_t) entityDim(int) entityTag(int) entityTagMaster(int) numAffine(size_t) value(double) ... numCorrespondingNodes(size_t) nodeTag(size_t) nodeTagMaster(size_t) ... ... $EndPeriodic """ def tofile(fh, value, dtype, **kwargs): ary = np.array(value, dtype=dtype) if binary: ary.tofile(fh) else: ary = np.atleast_2d(ary) fmt = float_fmt if dtype == c_double else "d" fmt = "%" + kwargs.pop("fmt", fmt) np.savetxt(fh, ary, fmt=fmt, **kwargs) fh.write(b"$Periodic\n") tofile(fh, len(periodic), c_size_t) for dim, (stag, mtag), affine, slave_master in periodic: tofile(fh, [dim, stag, mtag], c_int) if affine is None or len(affine) == 0: tofile(fh, 0, c_size_t) else: tofile(fh, len(affine), c_size_t, newline=" ") tofile(fh, affine, c_double, fmt=float_fmt) slave_master = np.array(slave_master, dtype=c_size_t) slave_master = slave_master.reshape(-1, 2) slave_master = slave_master + 1 # Add one, Gmsh is 1-based tofile(fh, len(slave_master), c_size_t) tofile(fh, slave_master, c_size_t) if binary: fh.write(b"\n") fh.write(b"$EndPeriodic\n") src/meshio/gmsh/common.py000066400000000000000000000210711456244072500157430ustar00rootroot00000000000000from __future__ import annotations import shlex import numpy as np from numpy.typing import ArrayLike from .._common import warn from .._exceptions import ReadError, WriteError c_int = np.dtype("int32") c_double = np.dtype("float64") def _fast_forward_to_end_block(f, block): """fast-forward to end of block""" # See also https://github.com/nschloe/pygalmesh/issues/34 for line in f: try: line = line.decode() except UnicodeDecodeError: pass if line.strip() == f"$End{block}": break else: warn(f"${block} not closed by $End{block}.") def _fast_forward_over_blank_lines(f): is_eof = False while True: line = f.readline().decode() if not line: is_eof = True break elif len(line.strip()) > 0: break return line, is_eof def _read_physical_names(f, field_data): line = f.readline().decode() num_phys_names = int(line) for _ in range(num_phys_names): line = shlex.split(f.readline().decode()) key = line[2] value = np.array(line[1::-1], dtype=int) field_data[key] = value _fast_forward_to_end_block(f, "PhysicalNames") def _read_data(f, tag, data_dict, data_size, is_ascii): # Read string tags num_string_tags = int(f.readline().decode()) string_tags = [ f.readline().decode().strip().replace('"', "") for _ in range(num_string_tags) ] # The real tags typically only contain one value, the time. # Discard it. num_real_tags = int(f.readline().decode()) for _ in range(num_real_tags): f.readline() num_integer_tags = int(f.readline().decode()) integer_tags = [int(f.readline().decode()) for _ in range(num_integer_tags)] num_components = integer_tags[1] num_items = integer_tags[2] if is_ascii: data = np.fromfile(f, count=num_items * (1 + num_components), sep=" ").reshape( (num_items, 1 + num_components) ) # The first entry is the node number data = data[:, 1:] else: # binary dtype = [("index", c_int), ("values", c_double, (num_components,))] data = np.fromfile(f, count=num_items, dtype=dtype) if not (data["index"] == range(1, num_items + 1)).all(): raise ReadError() data = np.ascontiguousarray(data["values"]) _fast_forward_to_end_block(f, tag) # The gmsh format cannot distinguish between data of shape (n,) and (n, 1). # If shape[1] == 1, cut it off. if data.shape[1] == 1: data = data[:, 0] data_dict[string_tags[0]] = data # Translate meshio types to gmsh codes # http://gmsh.info//doc/texinfo/gmsh.html#MSH-file-format-version-2 _gmsh_to_meshio_type = { 1: "line", 2: "triangle", 3: "quad", 4: "tetra", 5: "hexahedron", 6: "wedge", 7: "pyramid", 8: "line3", 9: "triangle6", 10: "quad9", 11: "tetra10", 12: "hexahedron27", 13: "wedge18", 14: "pyramid14", 15: "vertex", 16: "quad8", 17: "hexahedron20", 18: "wedge15", 19: "pyramid13", 21: "triangle10", 23: "triangle15", 25: "triangle21", 26: "line4", 27: "line5", 28: "line6", 29: "tetra20", 30: "tetra35", 31: "tetra56", 36: "quad16", 37: "quad25", 38: "quad36", 42: "triangle28", 43: "triangle36", 44: "triangle45", 45: "triangle55", 46: "triangle66", 47: "quad49", 48: "quad64", 49: "quad81", 50: "quad100", 51: "quad121", 62: "line7", 63: "line8", 64: "line9", 65: "line10", 66: "line11", 71: "tetra84", 72: "tetra120", 73: "tetra165", 74: "tetra220", 75: "tetra286", 90: "wedge40", 91: "wedge75", 92: "hexahedron64", 93: "hexahedron125", 94: "hexahedron216", 95: "hexahedron343", 96: "hexahedron512", 97: "hexahedron729", 98: "hexahedron1000", 106: "wedge126", 107: "wedge196", 108: "wedge288", 109: "wedge405", 110: "wedge550", } _meshio_to_gmsh_type = {v: k for k, v in _gmsh_to_meshio_type.items()} def _gmsh_to_meshio_order(cell_type: str, idx: ArrayLike) -> np.ndarray: # Gmsh cells are mostly ordered like VTK, with a few exceptions: meshio_ordering = { # fmt: off "tetra10": [0, 1, 2, 3, 4, 5, 6, 7, 9, 8], "hexahedron20": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 13, 9, 16, 18, 19, 17, 10, 12, 14, 15, ], # https://vtk.org/doc/release/4.2/html/classvtkQuadraticHexahedron.html and https://gmsh.info/doc/texinfo/gmsh.html#Node-ordering "hexahedron27": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 13, 9, 16, 18, 19, 17, 10, 12, 14, 15, 22, 23, 21, 24, 20, 25, 26, ], "wedge15": [ 0, 1, 2, 3, 4, 5, 6, 9, 7, 12, 14, 13, 8, 10, 11 ], # http://davis.lbl.gov/Manuals/VTK-4.5/classvtkQuadraticWedge.html and https://gmsh.info/doc/texinfo/gmsh.html#Node-ordering "pyramid13": [0, 1, 2, 3, 4, 5, 8, 10, 6, 7, 9, 11, 12], # fmt: on } idx = np.asarray(idx) if cell_type not in meshio_ordering: return idx return idx[:, meshio_ordering[cell_type]] def _meshio_to_gmsh_order(cell_type: str, idx: ArrayLike) -> np.ndarray: # Gmsh cells are mostly ordered like VTK, with a few exceptions: gmsh_ordering = { # fmt: off "tetra10": [0, 1, 2, 3, 4, 5, 6, 7, 9, 8], "hexahedron20": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 16, 9, 17, 10, 18, 19, 12, 15, 13, 14, ], "hexahedron27": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 16, 9, 17, 10, 18, 19, 12, 15, 13, 14, 24, 22, 20, 21, 23, 25, 26, ], "wedge15": [ 0, 1, 2, 3, 4, 5, 6, 8, 12, 7, 13, 14, 9, 11, 10, ], "pyramid13": [0, 1, 2, 3, 4, 5, 8, 9, 6, 10, 7, 11, 12], # fmt: on } idx = np.asarray(idx) if cell_type not in gmsh_ordering: return idx return idx[:, gmsh_ordering[cell_type]] def _write_physical_names(fh, field_data): # Write physical names entries = [] for phys_name in field_data: try: phys_num, phys_dim = field_data[phys_name] phys_num, phys_dim = int(phys_num), int(phys_dim) entries.append((phys_dim, phys_num, phys_name)) except (ValueError, TypeError): warn("Field data contains entry that cannot be processed.") entries.sort() if entries: fh.write(b"$PhysicalNames\n") fh.write(f"{len(entries)}\n".encode()) for entry in entries: fh.write('{} {} "{}"\n'.format(*entry).encode()) fh.write(b"$EndPhysicalNames\n") def _write_data(fh, tag, name, data, binary): fh.write(f"${tag}\n".encode()) # : # > Number of string tags. # > gives the number of string tags that follow. By default the first # > string-tag is interpreted as the name of the post-processing view and # > the second as the name of the interpolation scheme. The interpolation # > scheme is provided in the $InterpolationScheme section (see below). fh.write(f"{1}\n".encode()) fh.write(f'"{name}"\n'.encode()) fh.write(f"{1}\n".encode()) fh.write(f"{0.0}\n".encode()) # three integer tags: fh.write(f"{3}\n".encode()) # time step fh.write(f"{0}\n".encode()) # number of components num_components = data.shape[1] if len(data.shape) > 1 else 1 if num_components not in [1, 3, 9]: raise WriteError("Gmsh only permits 1, 3, or 9 components per data field.") # Cut off the last dimension in case it's 1. This avoids problems with # writing the data. if len(data.shape) > 1 and data.shape[1] == 1: data = data[:, 0] fh.write(f"{num_components}\n".encode()) # num data items fh.write(f"{data.shape[0]}\n".encode()) # actually write the data if binary: if num_components == 1: dtype = [("index", c_int), ("data", c_double)] else: dtype = [("index", c_int), ("data", c_double, num_components)] tmp = np.empty(len(data), dtype=dtype) tmp["index"] = 1 + np.arange(len(data)) tmp["data"] = data tmp.tofile(fh) fh.write(b"\n") else: fmt = " ".join(["{}"] + ["{!r}"] * num_components) + "\n" # TODO unify if num_components == 1: for k, x in enumerate(data): fh.write(fmt.format(k + 1, x).encode()) else: for k, x in enumerate(data): fh.write(fmt.format(k + 1, *x).encode()) fh.write(f"$End{tag}\n".encode()) src/meshio/gmsh/main.py000066400000000000000000000065571456244072500154130ustar00rootroot00000000000000import pathlib import struct from .._exceptions import ReadError, WriteError from .._helpers import register_format from . import _gmsh22, _gmsh40, _gmsh41 from .common import _fast_forward_to_end_block # Some mesh files out there have the version specified as version "2" when it really is # "2.2". Same with "4" vs "4.1". _readers = {"2": _gmsh22, "2.2": _gmsh22, "4.0": _gmsh40, "4": _gmsh41, "4.1": _gmsh41} _writers = {"2.2": _gmsh22, "4.0": _gmsh40, "4.1": _gmsh41} def read(filename): """Reads a Gmsh msh file.""" filename = pathlib.Path(filename) with open(filename.as_posix(), "rb") as f: mesh = read_buffer(f) return mesh def read_buffer(f): # The various versions of the format are specified at # . line = f.readline().decode().strip() # skip any $Comments/$EndComments sections while line == "$Comments": _fast_forward_to_end_block(f, "Comments") line = f.readline().decode().strip() if line != "$MeshFormat": raise ReadError() fmt_version, data_size, is_ascii = _read_header(f) try: reader = _readers[fmt_version] except KeyError: try: reader = _readers[fmt_version.split(".")[0]] except KeyError: raise ValueError( "Need mesh format in {} (got {})".format( sorted(_readers.keys()), fmt_version ) ) return reader.read_buffer(f, is_ascii, data_size) def _read_header(f): """Read the mesh format block specified as version(ASCII double; currently 4.1) file-type(ASCII int; 0 for ASCII mode, 1 for binary mode) data-size(ASCII int; sizeof(size_t)) < int with value one; only in binary mode, to detect endianness > though here the version is left as str """ # http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format line = f.readline().decode() # Split the line # 4.1 0 8 # into its components. str_list = list(filter(None, line.split())) fmt_version = str_list[0] if str_list[1] not in ["0", "1"]: raise ReadError() is_ascii = str_list[1] == "0" data_size = int(str_list[2]) if not is_ascii: # The next line is the integer 1 in bytes. Useful for checking endianness. # Just assert that we get 1 here. one = f.read(struct.calcsize("i")) if struct.unpack("i", one)[0] != 1: raise ReadError() _fast_forward_to_end_block(f, "MeshFormat") return fmt_version, data_size, is_ascii # Gmsh ASCII output uses `%.16g` for floating point values, # meshio uses same precision but exponential notation `%.16e`. def write(filename, mesh, fmt_version="4.1", binary=True, float_fmt=".16e"): """Writes a Gmsh msh file.""" try: writer = _writers[fmt_version] except KeyError: try: writer = _writers[fmt_version] except KeyError: raise WriteError( "Need mesh format in {} (got {})".format( sorted(_writers.keys()), fmt_version ) ) writer.write(filename, mesh, binary=binary, float_fmt=float_fmt) register_format( "gmsh", [".msh"], read, { "gmsh22": lambda f, m, **kwargs: write(f, m, "2.2", **kwargs), "gmsh": lambda f, m, **kwargs: write(f, m, "4.1", **kwargs), }, ) src/meshio/h5m/000077500000000000000000000000001456244072500136335ustar00rootroot00000000000000src/meshio/h5m/__init__.py000066400000000000000000000000731456244072500157440ustar00rootroot00000000000000from ._h5m import read, write __all__ = ["read", "write"] src/meshio/h5m/_h5m.py000066400000000000000000000213671456244072500150460ustar00rootroot00000000000000""" I/O for h5m, cf. . """ from datetime import datetime import numpy as np from .. import __about__ from .._common import warn from .._helpers import register_format from .._mesh import CellBlock, Mesh # def _int_to_bool_list(num): # # From . # bin_string = format(num, '04b') # return [x == '1' for x in bin_string[::-1]] def read(filename): import h5py f = h5py.File(filename, "r") dset = f["tstt"] points = dset["nodes"]["coordinates"][()] # read point data point_data = {} if "tags" in dset["nodes"]: for name, dataset in dset["nodes"]["tags"].items(): point_data[name] = dataset[()] # # Assert that the GLOBAL_IDs are contiguous. # point_gids = dset['nodes']['tags']['GLOBAL_ID'][()] # point_start_gid = dset['nodes']['coordinates'].attrs['start_id'] # point_end_gid = point_start_gid + len(point_gids) - 1 # assert all(point_gids == range(point_start_gid, point_end_gid + 1)) h5m_to_meshio_type = { "Edge2": "line", "Hex8": "hexahedron", "Prism6": "wedge", "Pyramid5": "pyramid", "Quad4": "quad", "Tri3": "triangle", "Tet4": "tetra", } cells = [] cell_data = {} for h5m_type, data in dset["elements"].items(): meshio_type = h5m_to_meshio_type[h5m_type] conn = data["connectivity"] # Note that the indices are off by 1 in h5m. cells.append(CellBlock(meshio_type, conn[()] - 1)) # TODO bring cell data back # if 'tags' in data: # for name, dataset in data['tags'].items(): # cell_data[name] = dataset[()] # The `sets` in H5M are special in that they represent a segration of data # in the current file, particularly by a load balancer (Metis, Zoltan, # etc.). This segregation has no equivalent in other data types, but is # certainly worthwhile visualizing. # Hence, we will translate the sets into cell data with the prefix "set::" # here. field_data = {} # TODO deal with sets # if 'sets' in dset and 'contents' in dset['sets']: # # read sets # sets_contents = dset['sets']['contents'][()] # sets_list = dset['sets']['list'][()] # sets_tags = dset['sets']['tags'] # cell_start_gid = conn.attrs['start_id'] # cell_gids = cell_start_gid + elems['tags']['GLOBAL_ID'][()] # cell_end_gid = cell_start_gid + len(cell_gids) - 1 # assert all(cell_gids == range(cell_start_gid, cell_end_gid + 1)) # # create the sets # for key, value in sets_tags.items(): # mod_key = 'set::' + key # cell_data[mod_key] = np.empty(len(cells), dtype=int) # end = 0 # for k, row in enumerate(sets_list): # bits = _int_to_bool_list(row[3]) # # is_owner = bits[0] # # is_unique = bits[1] # # is_ordered = bits[2] # is_range_compressed = bits[3] # if is_range_compressed: # start_gids = sets_contents[end:row[0]+1:2] # lengths = sets_contents[end+1:row[0]+1:2] # for start_gid, length in zip(start_gids, lengths): # end_gid = start_gid + length - 1 # if start_gid >= cell_start_gid and \ # end_gid <= cell_end_gid: # i0 = start_gid - cell_start_gid # i1 = end_gid - cell_start_gid + 1 # cell_data[mod_key][i0:i1] = value[k] # else: # # TODO deal with point data # raise RuntimeError('') # else: # gids = sets_contents[end:row[0]+1] # cell_data[mod_key][gids - cell_start_gid] = value[k] # end = row[0] + 1 return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data ) def write(filename, mesh, add_global_ids=True, compression="gzip", compression_opts=4): import h5py f = h5py.File(filename, "w") tstt = f.create_group("tstt") # The base index for h5m is 1. global_id = 1 # add nodes nodes = tstt.create_group("nodes") coords = nodes.create_dataset( "coordinates", data=mesh.points, compression=compression, compression_opts=compression_opts, ) coords.attrs.create("start_id", global_id) global_id += len(mesh.points) # Global tags tstt_tags = tstt.create_group("tags") # The GLOBAL_ID associated with a point is used to identify points if # distributed across several processes. mbpart automatically adds them, # too. # Copy to pd to avoid changing point_data. The items are not deep-copied. pd = mesh.point_data.copy() if "GLOBAL_ID" not in pd and add_global_ids: pd["GLOBAL_ID"] = np.arange(1, len(mesh.points) + 1) # add point data if pd: tags = nodes.create_group("tags") for key, data in pd.items(): if len(data.shape) == 1: dtype = data.dtype tags.create_dataset( key, data=data, compression=compression, compression_opts=compression_opts, ) else: # H5M doesn't accept n-x-k arrays as data; it wants an n-x-1 # array with k-tuples as entries. n, k = data.shape dtype = np.dtype((data.dtype, (k,))) dset = tags.create_dataset( key, (n,), dtype=dtype, compression=compression, compression_opts=compression_opts, ) dset[:] = data # Create entry in global tags g = tstt_tags.create_group(key) g["type"] = dtype # Add a class tag: # From # : # ``` # /* Was dense tag data in mesh database */ # define mhdf_DENSE_TYPE 2 # /** \brief Was sparse tag data in mesh database */ # #define mhdf_SPARSE_TYPE 1 # /** \brief Was bit-field tag data in mesh database */ # #define mhdf_BIT_TYPE 0 # /** \brief Unused */ # #define mhdf_MESH_TYPE 3 # g.attrs["class"] = 2 # add elements elements = tstt.create_group("elements") elem_dt = h5py.special_dtype( enum=( "i", { "Edge": 1, "Tri": 2, "Quad": 3, "Polygon": 4, "Tet": 5, "Pyramid": 6, "Prism": 7, "Knife": 8, "Hex": 9, "Polyhedron": 10, }, ) ) tstt["elemtypes"] = elem_dt tstt.create_dataset( "history", data=[ __name__.encode(), __about__.__version__.encode(), str(datetime.now()).encode(), ], compression=compression, compression_opts=compression_opts, ) # number of nodes to h5m name, element type meshio_to_h5m_type = { "line": {"name": "Edge2", "type": 1}, "triangle": {"name": "Tri3", "type": 2}, "tetra": {"name": "Tet4", "type": 5}, } for cell_block in mesh.cells: key = cell_block.type data = cell_block.data if key not in meshio_to_h5m_type: warn("Unsupported H5M element type '%s'. Skipping.", key) continue this_type = meshio_to_h5m_type[key] elem_group = elements.create_group(this_type["name"]) elem_group.attrs.create("element_type", this_type["type"], dtype=elem_dt) # h5m node indices are 1-based conn = elem_group.create_dataset( "connectivity", data=(data + 1), compression=compression, compression_opts=compression_opts, ) conn.attrs.create("start_id", global_id) global_id += len(data) # add cell data for cell_type, cd in mesh.cell_data.items(): if cd: tags = elem_group.create_group("tags") for key, value in cd.items(): tags.create_dataset( key, data=value, compression=compression, compression_opts=compression_opts, ) # add empty set -- MOAB wants this sets = tstt.create_group("sets") sets.create_group("tags") # set max_id tstt.attrs.create("max_id", global_id, dtype="u8") register_format("h5m", [".h5m"], read, {"h5m": write}) src/meshio/hmf/000077500000000000000000000000001456244072500137145ustar00rootroot00000000000000src/meshio/hmf/__init__.py000066400000000000000000000000731456244072500160250ustar00rootroot00000000000000from ._hmf import read, write __all__ = ["read", "write"] src/meshio/hmf/_hmf.py000066400000000000000000000104661456244072500152060ustar00rootroot00000000000000import meshio from .._common import cell_data_from_raw, raw_from_cell_data, warn from .._helpers import register_format from ..xdmf.common import meshio_to_xdmf_type, xdmf_to_meshio_type def read(filename): import h5py with h5py.File(filename, "r") as f: assert f.attrs["type"] == "hmf" assert f.attrs["version"] == "0.1-alpha" assert len(f) == 1, "only one domain supported for now" domain = f["domain"] assert len(domain) == 1, "only one grid supported for now" grid = domain["grid"] points = None cells = {} point_data = {} cell_data_raw = {} for key, value in grid.items(): if key[:8] == "Topology": cell_type = value.attrs["TopologyType"] cells[xdmf_to_meshio_type[cell_type]] = value[()] elif key == "Geometry": # TODO is GeometryType really needed? assert value.attrs["GeometryType"] in ["X", "XY", "XYZ"] points = value[()] elif key == "CellAttributes": for name, ca in value.items(): cell_data_raw[name] = ca[()] else: assert key == "NodeAttributes" for name, na in value.items(): point_data[name] = na[()] cell_data = cell_data_from_raw(cells, cell_data_raw) return meshio.Mesh( points, cells, point_data=point_data, cell_data=cell_data, ) def write_points_cells(filename, points, cells, **kwargs): write(filename, meshio.Mesh(points, cells), **kwargs) def write(filename, mesh, compression="gzip", compression_opts=4): import h5py warn("Experimental file format. Format can change at any time.") with h5py.File(filename, "w") as h5_file: h5_file.attrs["type"] = "hmf" h5_file.attrs["version"] = "0.1-alpha" domain = h5_file.create_group("domain") grid = domain.create_group("grid") _write_points(grid, mesh.points, compression, compression_opts) _write_cells(mesh.cells, grid, compression, compression_opts) _write_point_data(mesh.point_data, grid, compression, compression_opts) _write_cell_data(mesh.cell_data, grid, compression, compression_opts) def _write_points(grid, points, compression, compression_opts): geo = grid.create_dataset( "Geometry", data=points, compression=compression, compression_opts=compression_opts, ) geo.attrs["GeometryType"] = "XYZ"[: points.shape[1]] def _write_cells(cell_blocks, grid, compression, compression_opts): for k, cell_block in enumerate(cell_blocks): xdmf_type = meshio_to_xdmf_type[cell_block.type][0] topo = grid.create_dataset( f"Topology{k}", data=cell_block.data, compression=compression, compression_opts=compression_opts, ) topo.attrs["TopologyType"] = xdmf_type # In XDMF, the point/cell data are stored as # # # # out.h5:/data2 # # # # We cannot register multiple entries with the same name in HDF, so instead of # "Attribute", use # ``` # NodeAttributes # -> name0 + data0 # -> name1 + data0 # -> ... # CellAttributes # -> ... # ``` # Alternative: # ``` # NodeAttribute0 # -> name # -> data # NodeAttribute1 # -> name # -> data # ... # ``` # It's done similarly for Topologies (cells). # def _write_point_data(point_data, grid, compression, compression_opts): na = grid.create_group("NodeAttributes") for name, data in point_data.items(): na.create_dataset( name, data=data, compression=compression, compression_opts=compression_opts, ) def _write_cell_data(cell_data, grid, compression, compression_opts): raw = raw_from_cell_data(cell_data) ca = grid.create_group("CellAttributes") for name, data in raw.items(): ca.create_dataset( name, data=data, compression=compression, compression_opts=compression_opts, ) register_format( "hmf", [".hmf"], read, {"hmf": write}, ) src/meshio/mdpa/000077500000000000000000000000001456244072500140635ustar00rootroot00000000000000src/meshio/mdpa/__init__.py000066400000000000000000000000741456244072500161750ustar00rootroot00000000000000from ._mdpa import read, write __all__ = ["read", "write"] src/meshio/mdpa/_mdpa.py000066400000000000000000000401631456244072500155210ustar00rootroot00000000000000""" I/O for KratosMultiphysics's mdpa format, cf. . The MDPA format is unsuitable for fast consumption, this is why: . """ import numpy as np from .._common import num_nodes_per_cell, raw_from_cell_data, warn from .._exceptions import ReadError, WriteError from .._files import open_file from .._helpers import register_format from .._mesh import Mesh ## We check if we can read/write the mesh natively from Kratos # TODO: Implement native reading # Translate meshio types to KratosMultiphysics codes # Kratos uses the same node numbering of GiD pre and post processor # http://www-opale.inrialpes.fr/Aerochina/info/en/html-version/gid_11.html # https://github.com/KratosMultiphysics/Kratos/wiki/Mesh-node-ordering _mdpa_to_meshio_type = { "Line2D2": "line", "Line3D2": "line", "Triangle2D3": "triangle", "Triangle3D3": "triangle", "Quadrilateral2D4": "quad", "Quadrilateral3D4": "quad", "Tetrahedra3D4": "tetra", "Hexahedra3D8": "hexahedron", "Prism3D6": "wedge", "Line2D3": "line3", "Triangle2D6": "triangle6", "Triangle3D6": "triangle6", "Quadrilateral2D9": "quad9", "Quadrilateral3D9": "quad9", "Tetrahedra3D10": "tetra10", "Hexahedra3D27": "hexahedron27", "Point2D": "vertex", "Point3D": "vertex", "Quadrilateral2D8": "quad8", "Quadrilateral3D8": "quad8", "Hexahedra3D20": "hexahedron20", } _meshio_to_mdpa_type = { "line": "Line2D2", "triangle": "Triangle2D3", "quad": "Quadrilateral2D4", "tetra": "Tetrahedra3D4", "hexahedron": "Hexahedra3D8", "wedge": "Prism3D6", "line3": "Line2D3", "triangle6": "Triangle2D6", "quad9": "Quadrilateral2D9", "tetra10": "Tetrahedra3D10", "hexahedron27": "Hexahedra3D27", "vertex": "Point2D", "quad8": "Quadrilateral2D8", "hexahedron20": "Hexahedra3D20", } inverse_num_nodes_per_cell = {v: k for k, v in num_nodes_per_cell.items()} local_dimension_types = { "Line2D2": 1, "Line3D2": 1, "Triangle2D3": 2, "Triangle3D3": 2, "Quadrilateral2D4": 2, "Quadrilateral3D4": 2, "Tetrahedra3D4": 3, "Hexahedra3D8": 3, "Prism3D6": 3, "Line2D3": 1, "Triangle2D6": 2, "Triangle3D6": 2, "Quadrilateral2D9": 2, "Quadrilateral3D9": 2, "Tetrahedra3D10": 3, "Hexahedra3D27": 3, "Point2D": 0, "Point3D": 0, "Quadrilateral2D8": 2, "Quadrilateral3D8": 2, "Hexahedra3D20": 3, } def read(filename): """Reads a KratosMultiphysics mdpa file.""" # if (have_kratos is True): # TODO: Implement natively # pass # else: with open_file(filename, "rb") as f: mesh = read_buffer(f) return mesh def _read_nodes(f, is_ascii, data_size): # Count the number of nodes. This is _extremely_ ugly; we first read the _entire_ # file until "End Nodes". The crazy thing is that first counting the lines, then # skipping back to pos, and using fromfile there is _faster_ than accumulating the # points into a list and converting them to a numpy array afterwards. A point count # would be _really_ helpful here, but yeah, that's a fallacy of the format. # pos = f.tell() num_nodes = 0 while True: line = f.readline().decode() if "End Nodes" in line: break num_nodes += 1 f.seek(pos) points = np.fromfile(f, count=num_nodes * 4, sep=" ").reshape((num_nodes, 4)) # The first number is the index points = points[:, 1:] line = f.readline().decode() if line.strip() != "End Nodes": raise ReadError() return points def _read_cells(f, cells, is_ascii, cell_tags, environ=None): if not is_ascii: raise ReadError("Can only read ASCII cells") # First we try to identify the entity t = None if environ is not None: if environ.startswith("Begin Elements "): entity_name = environ[15:] for key in _mdpa_to_meshio_type: if key in entity_name: t = _mdpa_to_meshio_type[key] break elif environ.startswith("Begin Conditions "): entity_name = environ[17:] for key in _mdpa_to_meshio_type: if key in entity_name: t = _mdpa_to_meshio_type[key] break while True: line = f.readline().decode() if line.startswith("End Elements") or line.startswith("End Conditions"): break # data[0] gives the entity id # data[1] gives the property id # The rest are the ids of the nodes data = [int(k) for k in filter(None, line.split())] num_nodes_per_elem = len(data) - 2 # We use this in case not alternative if t is None: t = inverse_num_nodes_per_cell[num_nodes_per_elem] if len(cells) == 0 or t != cells[-1][0]: cells.append((t, [])) # Subtract one to account for the fact that python indices are 0-based. cells[-1][1].append(np.array(data[-num_nodes_per_elem:]) - 1) # Using the property id as tag if t not in cell_tags: cell_tags[t] = [] cell_tags[t].append([data[1]]) # Cannot convert cell_tags[key] to numpy array: There may be a # different number of tags for each cell. if line.strip() not in ["End Elements", "End Conditions"]: raise ReadError() def _prepare_cells(cells, cell_tags): # Declaring has additional data tag has_additional_tag_data = False # restrict to the standard two data items (physical, geometrical) output_cell_tags = {} for key in cell_tags: output_cell_tags[key] = {"gmsh:physical": [], "gmsh:geometrical": []} for item in cell_tags[key]: if len(item) > 0: output_cell_tags[key]["gmsh:physical"].append(item[0]) if len(item) > 1: output_cell_tags[key]["gmsh:geometrical"].append(item[1]) if len(item) > 2: has_additional_tag_data = True output_cell_tags[key]["gmsh:physical"] = np.array( output_cell_tags[key]["gmsh:physical"], dtype=int ) output_cell_tags[key]["gmsh:geometrical"] = np.array( output_cell_tags[key]["gmsh:geometrical"], dtype=int ) # Kratos cells are mostly ordered like VTK, with a few exceptions: if "hexahedron20" in cells: cells["hexahedron20"] = cells["hexahedron20"][ :, [0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 10, 9, 16, 19, 18, 17, 12, 13, 14, 15] ] if "hexahedron27" in cells: cells["hexahedron27"] = cells["hexahedron27"][ :, [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 10, 9, 16, 19, 18, 17, 12, 13, 14, 15, 22, 24, 21, 23, 20, 25, 26, ], ] return has_additional_tag_data # def _read_data(f, tag, data_dict, is_ascii): # if not is_ascii: # raise ReadError() # # Read string tags # num_string_tags = int(f.readline().decode()) # string_tags = [ # f.readline().decode().strip().replace('"', "") # for _ in range(num_string_tags) # ] # # The real tags typically only contain one value, the time. # # Discard it. # num_real_tags = int(f.readline().decode()) # for _ in range(num_real_tags): # f.readline() # num_integer_tags = int(f.readline().decode()) # integer_tags = [int(f.readline().decode()) for _ in range(num_integer_tags)] # num_components = integer_tags[1] # num_items = integer_tags[2] # # # Creating data # data = np.fromfile(f, count=num_items * (1 + num_components), sep=" ").reshape( # (num_items, 1 + num_components) # ) # # The first number is the index # data = data[:, 1:] # # line = f.readline().decode() # if line.strip() != f"End {tag}": # raise ReadError() # # # The gmsh format cannot distinguish between data of shape (n,) and (n, 1). # # If shape[1] == 1, cut it off. # if data.shape[1] == 1: # data = data[:, 0] # # data_dict[string_tags[0]] = data def read_buffer(f): # The format is specified at # . # Initialize the optional data fields points = [] cells = [] field_data = {} cell_data = {} # cell_data_raw = {} cell_tags = {} point_data = {} is_ascii = True data_size = None # Definition of cell tags cell_tags = {} # Saving position # pos = f.tell() # Read mesh while True: line = f.readline().decode() if not line: # EOF break environ = line.strip() if environ.startswith("Begin Nodes"): points = _read_nodes(f, is_ascii, data_size) elif environ.startswith("Begin Elements") or environ.startswith( "Begin Conditions" ): _read_cells(f, cells, is_ascii, cell_tags, environ) # We finally prepare the cells has_additional_tag_data = _prepare_cells(cells, cell_tags) # Reverting to the original position # f.seek(pos) # Read data # TODO: To implement # while False: # line = f.readline().decode() # if not line: # # EOF # break # # elif "NodalData" in environ and cells_prepared: # # _read_data(f, "NodalData", point_data, data_size, is_ascii) # # elif "Begin ElementalData" in environ: # # _read_data(f, "ElementalData", cell_data_raw, data_size, is_ascii) # # elif "Begin ConditionalData" in environ: # # _read_data(f, "ConditionalData", cell_data_raw, data_size, is_ascii) if has_additional_tag_data: warn("The file contains tag data that couldn't be processed.") # cell_data = cell_data_from_raw(cells, cell_data_raw) ## Merge cell_tags into cell_data # for key, tag_dict in cell_tags.items(): # if key not in cell_data: # cell_data[key] = {} # for name, item_list in tag_dict.items(): # assert name not in cell_data[key] # cell_data[key][name] = item_list return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data ) def cell_data_from_raw(cells, cell_data_raw): cell_data = {k: {} for k in cells} for key in cell_data_raw: d = cell_data_raw[key] r = 0 for k in cells: cell_data[k][key] = d[r : r + len(cells[k])] r += len(cells[k]) return cell_data def _write_nodes(fh, points, float_fmt, binary=False): fh.write(b"Begin Nodes\n") if binary: raise WriteError() for k, x in enumerate(points): fmt = " {} " + " ".join(3 * ["{:" + float_fmt + "}"]) + "\n" fh.write(fmt.format(k + 1, x[0], x[1], x[2]).encode()) fh.write(b"End Nodes\n\n") def _write_elements_and_conditions(fh, cells, tag_data, binary=False, dimension=2): if binary: raise WriteError("Can only write ASCII") # write elements entity = "Elements" dimension_name = f"{dimension}D" wrong_dimension_name = "3D" if dimension == 2 else "2D" consecutive_index = 0 for cell_block in cells: cell_type = cell_block.type node_idcs = cell_block.data # NOTE: The names of the dummy conditions are not regular, require extra work # local_dimension = local_dimension_types[cell_type] # if (local_dimension < dimension): # entity = "Conditions" mdpa_cell_type = _meshio_to_mdpa_type[cell_type].replace( wrong_dimension_name, dimension_name ) fh.write(f"Begin {entity} {mdpa_cell_type}\n".encode()) # TODO: Add proper tag recognition in the future fcd = np.empty((len(node_idcs), 0), dtype=np.int32) for k, c in enumerate(node_idcs): a1 = " ".join([str(val) for val in fcd[k]]) a2 = " ".join([str(cc) for cc in c + 1]) fh.write( f" {consecutive_index + k + 1} {fcd.shape[1]} {a1} {a2}\n".encode() ) consecutive_index += len(node_idcs) fh.write(f"End {entity}\n\n".encode()) def _write_data(fh, tag, name, data, binary): if binary: raise WriteError() fh.write(f"Begin {tag} {name}\n\n".encode()) # number of components num_components = data.shape[1] if len(data.shape) > 1 else 1 # Cut off the last dimension in case it's 1. This avoids problems with # writing the data. if len(data.shape) > 1 and data.shape[1] == 1: data = data[:, 0] # Actually write the data fmt = " ".join(["{}"] + ["{!r}"] * num_components) + "\n" # TODO unify if num_components == 1: for k, x in enumerate(data): fh.write(fmt.format(k + 1, x).encode()) else: for k, x in enumerate(data): fh.write(fmt.format(k + 1, *x).encode()) fh.write(f"End {tag} {name}\n\n".encode()) def write(filename, mesh, float_fmt=".16e", binary=False): """Writes mdpa files, cf. . """ if binary: raise WriteError() if mesh.points.shape[1] == 2: warn( "mdpa requires 3D points, but 2D points given. " "Appending 0 third component." ) points = np.column_stack([mesh.points, np.zeros_like(mesh.points[:, 0])]) else: points = mesh.points # Kratos cells are mostly ordered like VTK, with a few exceptions: cells = mesh.cells.copy() if "hexahedron20" in cells: cells["hexahedron20"] = cells["hexahedron20"][ :, [0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 10, 9, 16, 17, 18, 19, 12, 15, 14, 13] ] if "hexahedron27" in cells: cells["hexahedron27"] = cells["hexahedron27"][ :, [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 10, 9, 16, 17, 18, 19, 12, 15, 14, 13, 22, 24, 21, 23, 20, 25, 26, ], ] with open_file(filename, "wb") as fh: # Write some additional info fh.write(b"Begin ModelPartData\n") fh.write(b"// VARIABLE_NAME value\n") fh.write(b"End ModelPartData\n\n") fh.write(b"Begin Properties 0\n") fh.write(b"End Properties\n\n") # Split the cell data: gmsh:physical and gmsh:geometrical are tags, the # rest is actual cell data. tag_data = {} other_data = {} for key, data in mesh.cell_data.items(): if key in ["gmsh:physical", "gmsh:geometrical"]: tag_data[key] = [entry.astype(np.int32) for entry in data] else: other_data[key] = data # identity dimension dimension = 2 for c in cells: name_elem = _meshio_to_mdpa_type[c.type] if local_dimension_types[name_elem] == 3: dimension = 3 break # identify entities _write_nodes(fh, points, float_fmt, binary) _write_elements_and_conditions(fh, cells, tag_data, binary, dimension) for name, dat in mesh.point_data.items(): _write_data(fh, "NodalData", name, dat, binary) cell_data_raw = raw_from_cell_data(other_data) for name, dat in cell_data_raw.items(): # assume always that the components are elements (for now) _write_data(fh, "ElementalData", name, dat, binary) register_format("mdpa", [".mdpa"], read, {"mdpa": write}) src/meshio/med/000077500000000000000000000000001456244072500137075ustar00rootroot00000000000000src/meshio/med/__init__.py000066400000000000000000000000731456244072500160200ustar00rootroot00000000000000from ._med import read, write __all__ = ["read", "write"] src/meshio/med/_med.py000066400000000000000000000407071456244072500151750ustar00rootroot00000000000000""" I/O for MED/Salome, cf. . """ import numpy as np from .._common import num_nodes_per_cell from .._exceptions import ReadError, WriteError from .._helpers import register_format from .._mesh import Mesh # https://docs.salome-platform.org/5/med/dev/med__outils_8hxx.html meshio_to_med_type = { "vertex": "PO1", "line": "SE2", "line3": "SE3", "triangle": "TR3", "triangle6": "TR6", "quad": "QU4", "quad8": "QU8", "tetra": "TE4", "tetra10": "T10", "hexahedron": "HE8", "hexahedron20": "H20", "pyramid": "PY5", "pyramid13": "P13", "wedge": "PE6", "wedge15": "P15", } med_to_meshio_type = {v: k for k, v in meshio_to_med_type.items()} numpy_void_str = np.bytes_("") def read(filename): import h5py f = h5py.File(filename, "r") # Mesh ensemble mesh_ensemble = f["ENS_MAA"] meshes = mesh_ensemble.keys() if len(meshes) != 1: raise ReadError(f"Must only contain exactly 1 mesh, found {len(meshes)}.") mesh_name = list(meshes)[0] mesh = mesh_ensemble[mesh_name] dim = mesh.attrs["ESP"] # Possible time-stepping if "NOE" not in mesh: # One needs NOE (node) and MAI (French maillage, meshing) data. If they # are not available in the mesh, check for time-steppings. time_step = mesh.keys() if len(time_step) != 1: raise ReadError( f"Must only contain exactly 1 time-step, found {len(time_step)}." ) mesh = mesh[list(time_step)[0]] # Initialize data point_data = {} cell_data = {} field_data = {} # Points pts_dataset = mesh["NOE"]["COO"] n_points = pts_dataset.attrs["NBR"] points = pts_dataset[()].reshape((n_points, dim), order="F") # Point tags if "FAM" in mesh["NOE"]: tags = mesh["NOE"]["FAM"][()] point_data["point_tags"] = tags # replacing previous "point_tags" # Information for point tags point_tags = {} fas = mesh["FAS"] if "FAS" in mesh else f["FAS"][mesh_name] if "NOEUD" in fas: point_tags = _read_families(fas["NOEUD"]) # CellBlock cells = [] cell_types = [] med_cells = mesh["MAI"] for med_cell_type, med_cell_type_group in med_cells.items(): cell_type = med_to_meshio_type[med_cell_type] cell_types.append(cell_type) nod = med_cell_type_group["NOD"] n_cells = nod.attrs["NBR"] cells += [(cell_type, nod[()].reshape(n_cells, -1, order="F") - 1)] # Cell tags if "FAM" in med_cell_type_group: tags = med_cell_type_group["FAM"][()] if "cell_tags" not in cell_data: cell_data["cell_tags"] = [] cell_data["cell_tags"].append(tags) # Information for cell tags cell_tags = {} if "ELEME" in fas: cell_tags = _read_families(fas["ELEME"]) # Read nodal and cell data if they exist try: fields = f["CHA"] # champs (fields) in French except KeyError: pass else: profiles = f["PROFILS"] if "PROFILS" in f else None _read_data(fields, profiles, cell_types, point_data, cell_data, field_data) # Construct the mesh object mesh = Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data ) mesh.point_tags = point_tags mesh.cell_tags = cell_tags return mesh def _read_data(fields, profiles, cell_types, point_data, cell_data, field_data): for name, data in fields.items(): if "NOM" in data.attrs: if "med:nom" not in field_data: field_data["med:nom"] = [] field_data["med:nom"].append(data.attrs["NOM"].decode().split()) time_step = sorted(data.keys()) # associated time-steps if len(time_step) == 1: # single time-step names = [name] # do not change field name else: # many time-steps names = [None] * len(time_step) for i, key in enumerate(time_step): t = data[key].attrs["PDT"] # current time names[i] = name + f"[{i:d}] - {t:g}" # MED field can contain multiple types of data for i, key in enumerate(time_step): med_data = data[key] # at a particular time step name = names[i] for supp in med_data: if supp == "NOE": # continuous nodal (NOEU) data point_data[name] = _read_nodal_data(med_data, profiles) else: # Gauss points (ELGA) or DG (ELNO) data cell_type = med_to_meshio_type[supp.partition(".")[2]] assert cell_type in cell_types cell_index = cell_types.index(cell_type) if name not in cell_data: cell_data[name] = [None] * len(cell_types) cell_data[name][cell_index] = _read_cell_data( med_data[supp], profiles ) def _read_nodal_data(med_data, profiles): profile = med_data["NOE"].attrs["PFL"] data_profile = med_data["NOE"][profile] n_points = data_profile.attrs["NBR"] if profile.decode() == "MED_NO_PROFILE_INTERNAL": # default profile with everything values = data_profile["CO"][()].reshape(n_points, -1, order="F") else: n_data = profiles[profile].attrs["NBR"] index_profile = profiles[profile]["PFL"][()] - 1 values_profile = data_profile["CO"][()].reshape(n_data, -1, order="F") values = np.full((n_points, values_profile.shape[1]), np.nan) values[index_profile] = values_profile if values.shape[-1] == 1: # cut off for scalars values = values[:, 0] return values def _read_cell_data(med_data, profiles): profile = med_data.attrs["PFL"] data_profile = med_data[profile] n_cells = data_profile.attrs["NBR"] n_gauss_points = data_profile.attrs["NGA"] if profile.decode() == "MED_NO_PROFILE_INTERNAL": # default profile with everything values = data_profile["CO"][()].reshape(n_cells, n_gauss_points, -1, order="F") else: n_data = profiles[profile].attrs["NBR"] index_profile = profiles[profile]["PFL"][()] - 1 values_profile = data_profile["CO"][()].reshape( n_data, n_gauss_points, -1, order="F" ) values = np.full( (n_cells, values_profile.shape[1], values_profile.shape[2]), np.nan ) values[index_profile] = values_profile # Only 1 data point per cell, shape -> (n_cells, n_components) if n_gauss_points == 1: values = values[:, 0, :] if values.shape[-1] == 1: # cut off for scalars values = values[:, 0] return values def _read_families(fas_data): families = {} for _, node_set in fas_data.items(): set_id = node_set.attrs["NUM"] # unique set id n_subsets = node_set["GRO"].attrs["NBR"] # number of subsets nom_dataset = node_set["GRO"]["NOM"][()] # (n_subsets, 80) of int8 name = [None] * n_subsets for i in range(n_subsets): name[i] = "".join([chr(x) for x in nom_dataset[i]]).strip().rstrip("\x00") families[set_id] = name return families def write(filename, mesh): import h5py # MED doesn't support compression, # # compression = None f = h5py.File(filename, "w") # Strangely the version must be 3.0.x # Any version >= 3.1.0 will NOT work with SALOME 8.3 info = f.create_group("INFOS_GENERALES") info.attrs.create("MAJ", 3) info.attrs.create("MIN", 0) info.attrs.create("REL", 0) # Meshes mesh_ensemble = f.create_group("ENS_MAA") mesh_name = "mesh" med_mesh = mesh_ensemble.create_group(mesh_name) med_mesh.attrs.create("DIM", mesh.points.shape[1]) # mesh dimension med_mesh.attrs.create("ESP", mesh.points.shape[1]) # spatial dimension med_mesh.attrs.create("REP", 0) # cartesian coordinate system (repère in French) med_mesh.attrs.create("UNT", numpy_void_str) # time unit med_mesh.attrs.create("UNI", numpy_void_str) # spatial unit med_mesh.attrs.create("SRT", 1) # sorting type MED_SORT_ITDT # component names: names = ["X", "Y", "Z"][: mesh.points.shape[1]] med_mesh.attrs.create("NOM", np.bytes_("".join(f"{name:<16}" for name in names))) med_mesh.attrs.create("DES", np.bytes_("Mesh created with meshio")) med_mesh.attrs.create("TYP", 0) # mesh type (MED_NON_STRUCTURE) # Time-step step = "-0000000000000000001-0000000000000000001" # NDT NOR time_step = med_mesh.create_group(step) time_step.attrs.create("CGT", 1) time_step.attrs.create("NDT", -1) # no time step (-1) time_step.attrs.create("NOR", -1) # no iteration step (-1) time_step.attrs.create("PDT", -1.0) # current time # Points nodes_group = time_step.create_group("NOE") nodes_group.attrs.create("CGT", 1) nodes_group.attrs.create("CGS", 1) profile = "MED_NO_PROFILE_INTERNAL" nodes_group.attrs.create("PFL", np.bytes_(profile)) coo = nodes_group.create_dataset("COO", data=mesh.points.flatten(order="F")) coo.attrs.create("CGT", 1) coo.attrs.create("NBR", len(mesh.points)) # Point tags if "point_tags" in mesh.point_data: # only works for med -> med family = nodes_group.create_dataset("FAM", data=mesh.point_data["point_tags"]) family.attrs.create("CGT", 1) family.attrs.create("NBR", len(mesh.points)) # Cells (mailles in French) if len(mesh.cells) != len(np.unique([c.type for c in mesh.cells])): raise WriteError("MED files cannot have two sections of the same cell type.") cells_group = time_step.create_group("MAI") cells_group.attrs.create("CGT", 1) for k, cell_block in enumerate(mesh.cells): cell_type = cell_block.type cells = cell_block.data med_type = meshio_to_med_type[cell_type] med_cells = cells_group.create_group(med_type) med_cells.attrs.create("CGT", 1) med_cells.attrs.create("CGS", 1) med_cells.attrs.create("PFL", np.bytes_(profile)) nod = med_cells.create_dataset("NOD", data=cells.flatten(order="F") + 1) nod.attrs.create("CGT", 1) nod.attrs.create("NBR", len(cells)) # Cell tags if "cell_tags" in mesh.cell_data: # works only for med -> med family = med_cells.create_dataset( "FAM", data=mesh.cell_data["cell_tags"][k] ) family.attrs.create("CGT", 1) family.attrs.create("NBR", len(cells)) # Information about point and cell sets (familles in French) fas = f.create_group("FAS") families = fas.create_group(mesh_name) family_zero = families.create_group("FAMILLE_ZERO") # must be defined in any case family_zero.attrs.create("NUM", 0) # For point tags try: if len(mesh.point_tags) > 0: node = families.create_group("NOEUD") _write_families(node, mesh.point_tags) except AttributeError: pass # For cell tags try: if len(mesh.cell_tags) > 0: element = families.create_group("ELEME") _write_families(element, mesh.cell_tags) except AttributeError: pass # Write nodal/cell data fields = f.create_group("CHA") name_idx = 0 field_names = mesh.field_data["med:nom"] if "med:nom" in mesh.field_data else [] # Nodal data for name, data in mesh.point_data.items(): if name == "point_tags": # ignore point_tags already written under FAS continue supp = "NOEU" # nodal data field_name = field_names[name_idx] if field_names else None name_idx += 1 _write_data(fields, mesh_name, field_name, profile, name, supp, data) # Cell data # Only support writing ELEM fields with only 1 Gauss point per cell # Or ELNO (DG) fields defined at every node per cell for name, d in mesh.cell_data.items(): if name == "cell_tags": # ignore cell_tags already written under FAS continue for cell, data in zip(mesh.cells, d): # Determine the nature of the cell data # Either shape = (n_data, ) or (n_data, n_components) -> ELEM # or shape = (n_data, n_gauss_points, n_components) -> ELNO or ELGA med_type = meshio_to_med_type[cell.type] if data.ndim <= 2: supp = "ELEM" elif data.shape[1] == num_nodes_per_cell[cell.type]: supp = "ELNO" else: # general ELGA data defined at unknown Gauss points supp = "ELGA" field_name = field_names[name_idx] if field_names else None _write_data( fields, mesh_name, field_name, profile, name, supp, data, med_type, ) name_idx += 1 def _write_data( fields, mesh_name, field_name, profile, name, supp, data, med_type=None, ): # Skip for general ELGA fields defined at unknown Gauss points if supp == "ELGA": return # Field try: # a same MED field may contain fields of different natures field = fields.create_group(name) field.attrs.create("MAI", np.bytes_(mesh_name)) field.attrs.create("TYP", 6) # MED_FLOAT64 field.attrs.create("UNI", numpy_void_str) # physical unit field.attrs.create("UNT", numpy_void_str) # time unit n_components = 1 if data.ndim == 1 else data.shape[-1] field.attrs.create("NCO", n_components) # number of components # names = _create_component_names(n_components) # field.attrs.create("NOM", np.bytes_("".join(f"{name:<16}" for name in names))) if field_name: field.attrs.create( "NOM", np.bytes_("".join(f"{name:<16}" for name in field_name)) ) else: field.attrs.create("NOM", np.bytes_(f"{'':<16}")) # Time-step step = "0000000000000000000100000000000000000001" time_step = field.create_group(step) time_step.attrs.create("NDT", 1) # time step 1 time_step.attrs.create("NOR", 1) # iteration step 1 time_step.attrs.create("PDT", 0.0) # current time time_step.attrs.create("RDT", -1) # NDT of the mesh time_step.attrs.create("ROR", -1) # NOR of the mesh except ValueError: # name already exists field = fields[name] ts_name = list(field.keys())[-1] time_step = field[ts_name] # Field information if supp == "NOEU": typ = time_step.create_group("NOE") elif supp == "ELNO": typ = time_step.create_group("NOE." + med_type) else: # 'ELEM' with only 1 Gauss points! typ = time_step.create_group("MAI." + med_type) typ.attrs.create("GAU", numpy_void_str) # no associated Gauss points typ.attrs.create("PFL", np.bytes_(profile)) profile = typ.create_group(profile) profile.attrs.create("NBR", len(data)) # number of data if supp == "ELNO": profile.attrs.create("NGA", data.shape[1]) else: profile.attrs.create("NGA", 1) profile.attrs.create("GAU", numpy_void_str) # Dataset profile.create_dataset("CO", data=data.flatten(order="F")) def _create_component_names(n_components): """To be correctly read in a MED viewer, each component must be a string of width 16. Since we do not know the physical nature of the data, we just use V1, V2,... """ return [f"V{(i+1)}" for i in range(n_components)] def _family_name(set_id, name): """Return the FAM object name corresponding to the unique set id and a list of subset names """ return "FAM" + "_" + str(set_id) + "_" + "_".join(name) def _write_families(fm_group, tags): """Write point/cell tag information under FAS/[mesh_name]""" for set_id, name in tags.items(): family = fm_group.create_group(_family_name(set_id, name)) family.attrs.create("NUM", set_id) group = family.create_group("GRO") group.attrs.create("NBR", len(name)) # number of subsets dataset = group.create_dataset("NOM", (len(name),), dtype="80int8") for i in range(len(name)): # make name 80 characters name_80 = name[i] + "\x00" * (80 - len(name[i])) # Needs numpy array, see dataset[i] = np.array([ord(x) for x in name_80]) register_format("med", [".med"], read, {"med": write}) src/meshio/medit/000077500000000000000000000000001456244072500142445ustar00rootroot00000000000000src/meshio/medit/__init__.py000066400000000000000000000000751456244072500163570ustar00rootroot00000000000000from ._medit import read, write __all__ = ["read", "write"] src/meshio/medit/_medit.py000066400000000000000000000413711456244072500160650ustar00rootroot00000000000000""" I/O for Medit's format/Gamma Mesh Format, Latest official up-to-date documentation and a reference C implementation at """ import struct from ctypes import c_double, c_float import numpy as np from .._common import _pick_first_int_data, warn from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import Mesh from ._medit_internal import medit_codes def read(filename): with open_file(filename) as f: if str(filename)[-1] == "b": mesh = read_binary_buffer(f) else: mesh = read_ascii_buffer(f) return mesh def _produce_dtype(string_type, dim, itype, ftype): """ convert a medit_code to a dtype appropriate for building a numpy array """ res = "" c = 0 while c < len(string_type): s = string_type[c] if s == "i": res += itype elif s == "r": res += ftype elif s == "d": res += str(dim) c += 1 continue else: raise ReadError("Invalid string type") c += 1 if c != len(string_type): res += "," return res def read_binary_buffer(f): meshio_from_medit = { "GmfVertices": ("point", None), "GmfEdges": ("line", 2), "GmfTriangles": ("triangle", 3), "GmfQuadrilaterals": ("quad", 4), "GmfTetrahedra": ("tetra", 4), "GmfPrisms": ("wedge", 6), "GmfPyramids": ("pyramid", 5), "GmfHexahedra": ("hexahedron", 8), } dim = 0 points = None cells = [] point_data = {} cell_data = {"medit:ref": []} itype = "" ftype = "" postype = "" # the file version keytype = "i4" code = np.fromfile(f, count=1, dtype=keytype).item() if code != 1 and code != 16777216: raise ReadError("Invalid code") if code == 16777216: # swap endianness swapped = ">" if struct.unpack("=l", struct.pack(" 4: raise ReadError("Invalid version") if version == 1: itype += "i4" ftype += "f4" postype += "i4" elif version == 2: itype += "i4" ftype += "f8" postype += "i4" elif version == 3: itype += "i4" ftype += "f8" postype += "i8" else: itype += "i8" ftype += "f8" postype += "i8" field = np.fromfile(f, count=1, dtype=keytype).item() if field != 3: # = GmfDimension raise ReadError("Invalid dimension code : " + str(field) + " it should be 3") np.fromfile(f, count=1, dtype=postype) dim = np.fromfile(f, count=1, dtype=keytype).item() if dim != 2 and dim != 3: raise ReadError("Invalid mesh dimension : " + str(dim)) while True: field = np.fromfile(f, count=1, dtype=keytype) if field.size == 0: msg = "End-of-file reached before GmfEnd keyword" warn(msg) break field = field.item() if field not in medit_codes.keys(): raise ReadError("Unsupported field") field_code = medit_codes[field] if field_code[0] == "GmfEnd": break if field_code[0] == "GmfReserved": continue np.fromfile(f, count=1, dtype=postype) nitems = 1 if field_code[1] == "i": nitems = np.fromfile(f, count=1, dtype=itype).item() field_template = field_code[2] dtype = np.dtype(_produce_dtype(field_template, dim, itype, ftype)) out = np.asarray(np.fromfile(f, count=nitems, dtype=dtype)) if field_code[0] not in meshio_from_medit.keys(): warn(f"meshio doesn't know {field_code[0]} type. Skipping.") continue elif field_code[0] == "GmfVertices": points = out["f0"] point_data["medit:ref"] = out["f1"] else: meshio_type, ncols = meshio_from_medit[field_code[0]] # transform the structured array to integer array which suffices # for the cell connectivity out_view = out.view(itype).reshape(nitems, ncols + 1) cells.append((meshio_type, out_view[:, :ncols] - 1)) cell_data["medit:ref"].append(out_view[:, -1]) return Mesh(points, cells, point_data=point_data, cell_data=cell_data) def read_ascii_buffer(f): dim = 0 cells = [] point_data = {} cell_data = {"medit:ref": []} meshio_from_medit = { "Edges": ("line", 2), "Triangles": ("triangle", 3), "Quadrilaterals": ("quad", 4), "Tetrahedra": ("tetra", 4), "Prisms": ("wedge", 6), "Pyramids": ("pyramid", 5), "Hexahedra": ("hexahedron", 8), # Frey "Hexaedra": ("hexahedron", 8), # Dobrzynski } points = None dtype = None while True: line = f.readline() if not line: # EOF break line = line.strip() if len(line) == 0 or line[0] == "#": continue items = line.split() if not items[0].isalpha(): raise ReadError() if items[0] == "MeshVersionFormatted": version = items[1] dtype = {"0": c_float, "1": c_float, "2": c_double}[version] elif items[0] == "Dimension": if len(items) >= 2: dim = int(items[1]) else: dim = int( int(f.readline()) ) # e.g. Dimension\n3, where the number of dimensions is on the next line elif items[0] == "Vertices": if dim <= 0: raise ReadError() if dtype is None: raise ReadError("Expected `MeshVersionFormatted` before `Vertices`") num_verts = int(f.readline()) out = np.fromfile( f, count=num_verts * (dim + 1), dtype=dtype, sep=" " ).reshape(num_verts, dim + 1) points = out[:, :dim] point_data["medit:ref"] = out[:, dim].astype(int) elif items[0] in meshio_from_medit: meshio_type, points_per_cell = meshio_from_medit[items[0]] # The first value is the number of elements num_cells = int(f.readline()) out = np.fromfile( f, count=num_cells * (points_per_cell + 1), dtype=int, sep=" " ).reshape(num_cells, points_per_cell + 1) # adapt for 0-base cells.append((meshio_type, out[:, :points_per_cell] - 1)) cell_data["medit:ref"].append(out[:, -1]) elif items[0] == "Corners": # those are just discarded num_corners = int(f.readline()) np.fromfile(f, count=num_corners, dtype=dtype, sep=" ") elif items[0] == "Normals": # those are just discarded num_normals = int(f.readline()) np.fromfile(f, count=num_normals * dim, dtype=dtype, sep=" ").reshape( num_normals, dim ) elif items[0] == "NormalAtVertices": # those are just discarded num_normal_at_vertices = int(f.readline()) np.fromfile( f, count=num_normal_at_vertices * 2, dtype=int, sep=" " ).reshape(num_normal_at_vertices, 2) elif items[0] == "SubDomainFromMesh": # those are just discarded num_sub_domain_from_mesh = int(f.readline()) np.fromfile( f, count=num_sub_domain_from_mesh * 4, dtype=int, sep=" " ).reshape(num_sub_domain_from_mesh, 4) elif items[0] == "VertexOnGeometricVertex": # those are just discarded num_vertex_on_geometric_vertex = int(f.readline()) np.fromfile( f, count=num_vertex_on_geometric_vertex * 2, dtype=int, sep=" " ).reshape(num_vertex_on_geometric_vertex, 2) elif items[0] == "VertexOnGeometricEdge": # those are just discarded num_vertex_on_geometric_edge = int(f.readline()) np.fromfile( f, count=num_vertex_on_geometric_edge * 3, dtype=float, sep=" " ).reshape(num_vertex_on_geometric_edge, 3) elif items[0] == "EdgeOnGeometricEdge": # those are just discarded num_edge_on_geometric_edge = int(f.readline()) np.fromfile( f, count=num_edge_on_geometric_edge * 2, dtype=int, sep=" " ).reshape(num_edge_on_geometric_edge, 2) elif items[0] == "Identifier" or items[0] == "Geometry": f.readline() elif items[0] in [ "RequiredVertices", "TangentAtVertices", "Tangents", "Ridges", ]: msg = f"Meshio doesn't know keyword {items[0]}. Skipping." warn(msg) num_to_pass = int(f.readline()) for _ in range(num_to_pass): f.readline() else: if items[0] != "End": raise ReadError(f"Unknown keyword '{items[0]}'.") if points is None: raise ReadError("Expected `Vertices`") return Mesh(points, cells, point_data=point_data, cell_data=cell_data) def write(filename, mesh, float_fmt=".16e"): if str(filename)[-1] == "b": write_binary_file(filename, mesh) else: write_ascii_file(filename, mesh, float_fmt) def write_ascii_file(filename, mesh, float_fmt=".16e"): with open_file(filename, "wb") as fh: version = {np.dtype(c_float): 1, np.dtype(c_double): 2}[mesh.points.dtype] # N. B.: PEP 461 Adding % formatting to bytes and bytearray fh.write(f"MeshVersionFormatted {version}\n".encode()) n, d = mesh.points.shape fh.write(f"Dimension {d}\n".encode()) # vertices fh.write(b"\nVertices\n") fh.write(f"{n}\n".encode()) # pick out point data labels_key, other = _pick_first_int_data(mesh.point_data) if labels_key and other: string = ", ".join(other) warn( "Medit can only write one point data array. " f"Picking {labels_key}, skipping {string}." ) labels = mesh.point_data[labels_key] if labels_key else np.ones(n, dtype=int) fmt = " ".join(["{:" + float_fmt + "}"] * d) + " {:d}\n" for x, label in zip(mesh.points, labels): fh.write(fmt.format(*x, label).encode()) medit_from_meshio = { "line": ("Edges", 2), "triangle": ("Triangles", 3), "quad": ("Quadrilaterals", 4), "tetra": ("Tetrahedra", 4), "wedge": ("Prisms", 6), "pyramid": ("Pyramids", 5), "hexahedron": ("Hexahedra", 8), } # pick out cell_data labels_key, other = _pick_first_int_data(mesh.cell_data) if labels_key and other: string = ", ".join(other) warn( "Medit can only write one cell data array. " f"Picking {labels_key}, skipping {string}." ) for k, cell_block in enumerate(mesh.cells): cell_type = cell_block.type data = cell_block.data try: medit_name, num = medit_from_meshio[cell_type] except KeyError: msg = f"MEDIT's mesh format doesn't know {cell_type} cells. Skipping." warn(msg) continue fh.write(b"\n") fh.write(f"{medit_name}\n".encode()) fh.write(f"{len(data)}\n".encode()) # pick out cell data labels = ( mesh.cell_data[labels_key][k] if labels_key else np.ones(len(data), dtype=data.dtype) ) fmt = " ".join(["{:d}"] * (num + 1)) + "\n" # adapt 1-base for d, label in zip(data + 1, labels): fh.write(fmt.format(*d, label).encode()) fh.write(b"\nEnd\n") def write_binary_file(f, mesh): with open_file(f, "wb") as fh: version = 3 itype = "i4" postype = "i8" ftype = "f8" # according to manual keywords are always written as i4 independently of # the file version keytype = "i4" # if we store internally 64bit integers upgrade file version has_big_ints = False for cell_block in mesh.cells: if cell_block.data.dtype.itemsize == 8: has_big_ints = True break if has_big_ints: itype = "i8" version = 4 itype_size = np.dtype(itype).itemsize ftype_size = np.dtype(ftype).itemsize postype_size = np.dtype(postype).itemsize keyword_size = np.dtype(keytype).itemsize code = 1 field = 3 # GmfDimension pos = 4 * keyword_size + postype_size num_verts, dim = mesh.points.shape header_type = np.dtype(",".join([keytype, keytype, keytype, postype, keytype])) tmp_array = np.empty(1, dtype=header_type) tmp_array["f0"] = code tmp_array["f1"] = version tmp_array["f2"] = field tmp_array["f3"] = pos tmp_array["f4"] = dim tmp_array.tofile(fh) # write points field = 4 # GmfVertices field_code = medit_codes[field] pos += num_verts * dim * ftype_size pos += num_verts * itype_size pos += keyword_size + postype_size + itype_size header_type = np.dtype(",".join([keytype, postype, itype])) tmp_array = np.empty(1, dtype=header_type) tmp_array["f0"] = field tmp_array["f1"] = pos tmp_array["f2"] = num_verts tmp_array.tofile(fh) field_template = field_code[2] dtype = np.dtype(_produce_dtype(field_template, dim, itype, ftype)) labels_key, other = _pick_first_int_data(mesh.point_data) if labels_key and other: other_string = ", ".join(other) warn( "Medit can only write one point data array. " f"Picking {labels_key}, skipping {other_string}." ) labels = ( mesh.point_data[labels_key] if labels_key else np.ones(num_verts, dtype=itype) ) tmp_array = np.empty(num_verts, dtype=dtype) tmp_array["f0"] = mesh.points tmp_array["f1"] = labels tmp_array.tofile(fh) labels_key, other = _pick_first_int_data(mesh.cell_data) if labels_key and other: string = ", ".join(other) warn( "Medit can only write one cell data array. " f"Picking {labels_key}, skipping {string}." ) # first component is medit keyword id see _medit_internal.py medit_from_meshio = { "line": 5, "triangle": 6, "quad": 7, "tetra": 8, "wedge": 9, "pyramid": 49, "hexahedron": 10, } for k, cell_block in enumerate(mesh.cells): try: medit_key = medit_from_meshio[cell_block.type] except KeyError: warn( f"MEDIT's mesh format doesn't know {cell_block.type} cells. " + "Skipping." ) continue num_cells, num_verts = cell_block.data.shape pos += num_cells * (num_verts + 1) * itype_size pos += keyword_size + postype_size + itype_size header_type = np.dtype(",".join([keytype, postype, itype])) tmp_array = np.empty(1, dtype=header_type) tmp_array["f0"] = medit_key tmp_array["f1"] = pos tmp_array["f2"] = num_cells tmp_array.tofile(fh) # pick out cell data labels = ( mesh.cell_data[labels_key][k] if labels_key else np.ones(len(cell_block.data), dtype=cell_block.data.dtype) ) field_template = medit_codes[medit_key][2] dtype = np.dtype(_produce_dtype(field_template, dim, itype, ftype)) tmp_array = np.empty(num_cells, dtype=dtype) i = 0 for col_type in dtype.names[:-1]: tmp_array[col_type] = cell_block.data[:, i] + 1 i += 1 tmp_array[dtype.names[-1]] = labels tmp_array.tofile(fh) pos = 0 field = 54 # GmfEnd header_type = np.dtype(",".join([keytype, postype])) tmp_array = np.empty(1, dtype=header_type) tmp_array["f0"] = field tmp_array["f1"] = pos tmp_array.tofile(fh) register_format("medit", [".mesh", ".meshb"], read, {"medit": write}) src/meshio/medit/_medit_internal.py000066400000000000000000000244271456244072500177640ustar00rootroot00000000000000# Key is the enum value of each keyword # values follow the design of GmfKwdFmt array of # https://github.com/LoicMarechal/libMeshb/blob/master/sources/libmeshb7.c # For each keyword we assign whether there is a counter associated with it (second column) and # its format as a string of numbers # # i:integer, f:float, d:dimension medit_codes = { 0: ("GmfReserved", "", ""), 1: ("GmfMeshVersionFormatted", "", "i"), 2: ("GmfReserved", "", ""), 3: ("GmfDimension", "", "i"), 4: ("GmfVertices", "i", "dri"), 5: ("GmfEdges", "i", "iii"), 6: ("GmfTriangles", "i", "iiii"), 7: ("GmfQuadrilaterals", "i", "iiiii"), 8: ("GmfTetrahedra", "i", "iiiii"), 9: ("GmfPrisms", "i", "iiiiiii"), 10: ("GmfHexahedra", "i", "iiiiiiiii"), 11: ("GmfReserved", "", ""), 12: ("GmfReserved", "", ""), 13: ("GmfCorners", "i", "i"), 14: ("GmfRidges", "i", "i"), 15: ("GmfRequiredVertices", "i", "i"), 16: ("GmfRequiredEdges", "i", "i"), 17: ("GmfRequiredTriangles", "i", "i"), 18: ("GmfRequiredQuadrilaterals", "i", "i"), 19: ("GmfTangentAtEdgeVertices", "i", "iii"), 20: ("GmfNormalAtVertices", "i", "ii"), 21: ("GmfNormalAtTriangleVertices", "i", "iii"), 22: ("GmfNormalAtQuadrilateralVertices", "i", "iiii"), 23: ("GmfAngleOfCornerBound", "", "r"), 24: ("GmfTrianglesP2", "i", "iiiiiii"), 25: ("GmfEdgesP2", "i", "iiii"), 26: ("GmfSolAtPyramids", "i", "sr"), 27: ("GmfQuadrilateralsQ2", "i", "iiiiiiiiii"), 28: ("GmfISolAtPyramids", "i", "iiiii"), 29: ("GmfSubDomainFromGeom", "i", "iii"), 30: ("GmfTetrahedraP2", "i", "iiiiiiiiiii"), 31: ("GmfFault_NearTri", "i", "i"), 32: ("GmfFault_Inter", "i", "i"), 33: ("GmfHexahedraQ2", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiii"), 34: ("GmfExtraVerticesAtEdges", "i", "in"), 35: ("GmfExtraVerticesAtTriangles", "i", "in"), 36: ("GmfExtraVerticesAtQuadrilaterals", "i", "in"), 37: ("GmfExtraVerticesAtTetrahedra", "i", "in"), 38: ("GmfExtraVerticesAtPrisms", "i", "in"), 39: ("GmfExtraVerticesAtHexahedra", "i", "in"), 40: ("GmfVerticesOnGeometricVertices", "i", "ii"), 41: ("GmfVerticesOnGeometricEdges", "i", "iirr"), 42: ("GmfVerticesOnGeometricTriangles", "i", "iirrr"), 43: ("GmfVerticesOnGeometricQuadrilaterals", "i", "iirrr"), 44: ("GmfEdgesOnGeometricEdges", "i", "ii"), 45: ("GmfFault_FreeEdge", "i", "i"), 46: ("GmfPolyhedra", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"), 47: ("GmfPolygons", "", "iiiiiiiii"), 48: ("GmfFault_Overlap", "i", "i"), 49: ("GmfPyramids", "i", "iiiiii"), 50: ("GmfBoundingBox", "", "drdr"), 51: ("GmfReserved", "", ""), 52: ("GmfPrivateTable", "i", "i"), 53: ("GmfFault_BadShape", "i", "i"), 54: ("GmfEnd", "", ""), 55: ("GmfTrianglesOnGeometricTriangles", "i", "ii"), 56: ("GmfTrianglesOnGeometricQuadrilaterals", "i", "ii"), 57: ("GmfQuadrilateralsOnGeometricTriangles", "i", "ii"), 58: ("GmfQuadrilateralsOnGeometricQuadrilaterals", "i", "ii"), 59: ("GmfTangents", "i", "dr"), 60: ("GmfNormals", "i", "dr"), 61: ("GmfTangentAtVertices", "i", "ii"), 62: ("GmfSolAtVertices", "i", "sr"), 63: ("GmfSolAtEdges", "i", "sr"), 64: ("GmfSolAtTriangles", "i", "sr"), 65: ("GmfSolAtQuadrilaterals", "i", "sr"), 66: ("GmfSolAtTetrahedra", "i", "sr"), 67: ("GmfSolAtPrisms", "i", "sr"), 68: ("GmfSolAtHexahedra", "i", "sr"), 69: ("GmfDSolAtVertices", "i", "sr"), 70: ("GmfISolAtVertices", "i", "i"), 71: ("GmfISolAtEdges", "i", "ii"), 72: ("GmfISolAtTriangles", "i", "iii"), 73: ("GmfISolAtQuadrilaterals", "i", "iiii"), 74: ("GmfISolAtTetrahedra", "i", "iiii"), 75: ("GmfISolAtPrisms", "i", "iiiiii"), 76: ("GmfISolAtHexahedra", "i", "iiiiiiii"), 77: ("GmfIterations", "", "i"), 78: ("GmfTime", "", "r"), 79: ("GmfFault_SmallTri", "i", "i"), 80: ("GmfCoarseHexahedra", "i", "i"), 81: ("GmfComments", "i", "c"), 82: ("GmfPeriodicVertices", "i", "ii"), 83: ("GmfPeriodicEdges", "i", "ii"), 84: ("GmfPeriodicTriangles", "i", "ii"), 85: ("GmfPeriodicQuadrilaterals", "i", "ii"), 86: ("GmfPrismsP2", "i", "iiiiiiiiiiiiiiiiiii"), 87: ("GmfPyramidsP2", "i", "iiiiiiiiiiiiiii"), 88: ("GmfQuadrilateralsQ3", "i", "iiiiiiiiiiiiiiiii"), 89: ("GmfQuadrilateralsQ4", "i", "iiiiiiiiiiiiiiiiiiiiiiiiii"), 90: ("GmfTrianglesP3", "i", "iiiiiiiiiii"), 91: ("GmfTrianglesP4", "i", "iiiiiiiiiiiiiiii"), 92: ("GmfEdgesP3", "i", "iiiii"), 93: ("GmfEdgesP4", "i", "iiiiii"), 94: ("GmfIRefGroups", "i", "ciii"), 95: ("GmfDRefGroups", "i", "iii"), 96: ("GmfTetrahedraP3", "i", "iiiiiiiiiiiiiiiiiiiii"), 97: ("GmfTetrahedraP4", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"), 98: ( "GmfHexahedraQ3", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii", ), 99: ( "GmfHexahedraQ4", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii", ), 100: ("GmfPyramidsP3", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"), 101: ( "GmfPyramidsP4", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii", ), 102: ("GmfPrismsP3", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"), 103: ( "GmfPrismsP4", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii", ), 104: ("GmfHOSolAtEdgesP1", "i", "hr"), 105: ("GmfHOSolAtEdgesP2", "i", "hr"), 106: ("GmfHOSolAtEdgesP3", "i", "hr"), 107: ("GmfHOSolAtTrianglesP1", "i", "hr"), 108: ("GmfHOSolAtTrianglesP2", "i", "hr"), 109: ("GmfHOSolAtTrianglesP3", "i", "hr"), 110: ("GmfHOSolAtQuadrilateralsQ1", "i", "hr"), 111: ("GmfHOSolAtQuadrilateralsQ2", "i", "hr"), 112: ("GmfHOSolAtQuadrilateralsQ3", "i", "hr"), 113: ("GmfHOSolAtTetrahedraP1", "i", "hr"), 114: ("GmfHOSolAtTetrahedraP2", "i", "hr"), 115: ("GmfHOSolAtTetrahedraP3", "i", "hr"), 116: ("GmfHOSolAtPyramidsP1", "i", "hr"), 117: ("GmfHOSolAtPyramidsP2", "i", "hr"), 118: ("GmfHOSolAtPyramidsP3", "i", "hr"), 119: ("GmfHOSolAtPrismsP1", "i", "hr"), 120: ("GmfHOSolAtPrismsP2", "i", "hr"), 121: ("GmfHOSolAtPrismsP3", "i", "hr"), 122: ("GmfHOSolAtHexahedraQ1", "i", "hr"), 123: ("GmfHOSolAtHexahedraQ2", "i", "hr"), 124: ("GmfHOSolAtHexahedraQ3", "i", "hr"), 125: ("GmfBezierBasis", "", "i"), 126: ("GmfByteFlow", "i", "i"), 127: ("GmfEdgesP2Ordering", "i", "i"), 128: ("GmfEdgesP3Ordering", "i", "i"), 129: ("GmfTrianglesP2Ordering", "i", "iii"), 130: ("GmfTrianglesP3Ordering", "i", "iii"), 131: ("GmfQuadrilateralsQ2Ordering", "i", "ii"), 132: ("GmfQuadrilateralsQ3Ordering", "i", "ii"), 133: ("GmfTetrahedraP2Ordering", "i", "iiii"), 134: ("GmfTetrahedraP3Ordering", "i", "iiii"), 135: ("GmfPyramidsP2Ordering", "i", "iii"), 136: ("GmfPyramidsP3Ordering", "i", "iii"), 137: ("GmfPrismsP2Ordering", "i", "iiii"), 138: ("GmfPrismsP3Ordering", "i", "iiii"), 139: ("GmfHexahedraQ2Ordering", "i", "iii"), 140: ("GmfHexahedraQ3Ordering", "i", "iii"), 141: ("GmfEdgesP1Ordering", "i", "i"), 142: ("GmfEdgesP4Ordering", "i", "i"), 143: ("GmfTrianglesP1Ordering", "i", "iii"), 144: ("GmfTrianglesP4Ordering", "i", "iii"), 145: ("GmfQuadrilateralsQ1Ordering", "i", "ii"), 146: ("GmfQuadrilateralsQ4Ordering", "i", "ii"), 147: ("GmfTetrahedraP1Ordering", "i", "iiii"), 148: ("GmfTetrahedraP4Ordering", "i", "iiii"), 149: ("GmfPyramidsP1Ordering", "i", "iii"), 150: ("GmfPyramidsP4Ordering", "i", "iii"), 151: ("GmfPrismsP1Ordering", "i", "iiii"), 152: ("GmfPrismsP4Ordering", "i", "iiii"), 153: ("GmfHexahedraQ1Ordering", "i", "iii"), 154: ("GmfHexahedraQ4Ordering", "i", "iii"), 155: ("GmfFloatingPointPrecision", "", "i"), 156: ("GmfHOSolAtEdgesP4", "i", "hr"), 157: ("GmfHOSolAtTrianglesP4", "i", "hr"), 158: ("GmfHOSolAtQuadrilateralsQ4", "i", "hr"), 159: ("GmfHOSolAtTetrahedraP4", "i", "hr"), 160: ("GmfHOSolAtPyramidsP4", "i", "hr"), 161: ("GmfHOSolAtPrismsP4", "i", "hr"), 162: ("GmfHOSolAtHexahedraQ4", "i", "hr"), 163: ("GmfHOSolAtEdgesP1NodesPositions", "i", "rr"), 164: ("GmfHOSolAtEdgesP2NodesPositions", "i", "rr"), 165: ("GmfHOSolAtEdgesP3NodesPositions", "i", "rr"), 166: ("GmfHOSolAtEdgesP4NodesPositions", "i", "rr"), 167: ("GmfHOSolAtTrianglesP1NodesPositions", "i", "rrr"), 168: ("GmfHOSolAtTrianglesP2NodesPositions", "i", "rrr"), 169: ("GmfHOSolAtTrianglesP3NodesPositions", "i", "rrr"), 170: ("GmfHOSolAtTrianglesP4NodesPositions", "i", "rrr"), 171: ("GmfHOSolAtQuadrilateralsQ1NodesPositions", "i", "rr"), 172: ("GmfHOSolAtQuadrilateralsQ2NodesPositions", "i", "rr"), 173: ("GmfHOSolAtQuadrilateralsQ3NodesPositions", "i", "rr"), 174: ("GmfHOSolAtQuadrilateralsQ4NodesPositions", "i", "rr"), 175: ("GmfHOSolAtTetrahedraP1NodesPositions", "i", "rrrr"), 176: ("GmfHOSolAtTetrahedraP2NodesPositions", "i", "rrrr"), 177: ("GmfHOSolAtTetrahedraP3NodesPositions", "i", "rrrr"), 178: ("GmfHOSolAtTetrahedraP4NodesPositions", "i", "rrrr"), 179: ("GmfHOSolAtPyramidsP1NodesPositions", "i", "rrr"), 180: ("GmfHOSolAtPyramidsP2NodesPositions", "i", "rrr"), 181: ("GmfHOSolAtPyramidsP3NodesPositions", "i", "rrr"), 182: ("GmfHOSolAtPyramidsP4NodesPositions", "i", "rrr"), 183: ("GmfHOSolAtPrismsP1NodesPositions", "i", "rrrr"), 184: ("GmfHOSolAtPrismsP2NodesPositions", "i", "rrrr"), 185: ("GmfHOSolAtPrismsP3NodesPositions", "i", "rrrr"), 186: ("GmfHOSolAtPrismsP4NodesPositions", "i", "rrrr"), 187: ("GmfHOSolAtHexahedraQ1NodesPositions", "i", "rrr"), 188: ("GmfHOSolAtHexahedraQ2NodesPositions", "i", "rrr"), 189: ("GmfHOSolAtHexahedraQ3NodesPositions", "i", "rrr"), 190: ("GmfHOSolAtHexahedraQ4NodesPositions", "i", "rrr"), 191: ("GmfEdgesReferenceElement", "", "rr"), 192: ("GmfTriangleReferenceElement", "", "rrrrrr"), 193: ("GmfQuadrilateralReferenceElement", "", "rrrrrrrr"), 194: ("GmfTetrahedronReferenceElement", "", "rrrrrrrrrrrr"), 195: ("GmfPyramidReferenceElement", "", "rrrrrrrrrrrrrrr"), 196: ("GmfPrismReferenceElement", "", "rrrrrrrrrrrrrrrrrr"), 197: ("GmfHexahedronReferenceElement", "", "rrrrrrrrrrrrrrrrrrrrrrrr"), 198: ("GmfBoundaryLayers", "i", "iii"), } src/meshio/nastran/000077500000000000000000000000001456244072500146105ustar00rootroot00000000000000src/meshio/nastran/__init__.py000066400000000000000000000000771456244072500167250ustar00rootroot00000000000000from ._nastran import read, write __all__ = ["read", "write"] src/meshio/nastran/_nastran.py000066400000000000000000000432271456244072500167770ustar00rootroot00000000000000""" I/O for Nastran bulk data. """ from __future__ import annotations import numpy as np from ..__about__ import __version__ from .._common import num_nodes_per_cell, warn from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh nastran_to_meshio_type = { "CELAS1": "vertex", "CBEAM": "line", "CBUSH": "line", "CBUSH1D": "line", "CROD": "line", "CGAP": "line", "CBAR": "line", "CTRIAR": "triangle", "CTRIA3": "triangle", "CTRAX6": "triangle6", "CTRIAX6": "triangle6", "CTRIA6": "triangle6", "CQUADR": "quad", "CSHEAR": "quad", "CQUAD4": "quad", "CQUAD8": "quad8", "CQUAD9": "quad9", "CTETRA": "tetra", "CTETRA_": "tetra10", # fictive "CPYRAM": "pyramid", "CPYRA": "pyramid", "CPYRA_": "pyramid13", # fictive "CPENTA": "wedge", "CPENTA_": "wedge15", # fictive "CHEXA": "hexahedron", "CHEXA_": "hexahedron20", # fictive } nastran_solid_types = ["CTETRA", "CPYRA", "CPENTA", "CHEXA"] meshio_to_nastran_type = {v: k for k, v in nastran_to_meshio_type.items()} def read(filename): with open_file(filename, "r") as f: out = read_buffer(f) return out def read_buffer(f): # Skip until BEGIN BULK while True: line = f.readline() if not line: raise RuntimeError('"BEGIN BULK" statement not found') if line.strip().startswith("BEGIN BULK"): break # Reading data points = [] points_id = [] cells = [] cells_id = [] cell = None point_refs = [] cell_refs = [] cell_ref = None def add_cell(nastran_type, cell, cell_ref): cell_type = nastran_to_meshio_type[nastran_type] cell = list(map(int, cell)) # Treat 2nd order CTETRA, CPYRA, CPENTA, CHEXA elements if len(cell) > num_nodes_per_cell[cell_type]: assert cell_type in [ "tetra", "pyramid", "wedge", "hexahedron", ], f"Illegal cell type {cell_type}" if cell_type == "tetra": cell_type = "tetra10" nastran_type = "CTETRA_" elif cell_type == "pyramid": cell_type = "pyramid13" nastran_type = "CPYRA_" elif cell_type == "wedge": cell_type = "wedge15" nastran_type = "CPENTA_" elif cell_type == "hexahedron": cell_type = "hexahedron20" nastran_type = "CHEXA_" cell = _convert_to_vtk_ordering(cell, nastran_type) # decide if we should append cell or start a new cell block if len(cells) > 0 and cells[-1][0] == cell_type: cells[-1][1].append(cell) cells_id[-1].append(cell_id) if cell_ref is not None: cell_refs[-1].append(cell_ref) else: cells.append((cell_type, [cell])) cells_id.append([cell_id]) if cell_ref is not None: cell_refs.append([cell_ref]) while True: next_line = f.readline() # Blank lines or comments if len(next_line) < 4 or next_line.startswith(("$", "//", "#")): continue else: break while True: # End loop when ENDDATA detected if next_line.startswith("ENDDATA"): break # read line and merge with all continuation lines (starting with `+` or # `*` or automatic continuation lines in fixed format) chunks = [] c, _ = _chunk_line(next_line) chunks.append(c) while True: next_line = f.readline() if not next_line: raise ReadError("Premature EOF") # Blank lines or comments if len(next_line) < 4 or next_line.startswith(("$", "//", "#")): continue elif next_line[0] in ["+", "*"]: # From # : # You can manually specify a continuation by using a # continuation identifier. A continuation identifier is a # special character (+ or *) that indicates that the data # continues on another line. assert len(chunks[-1]) <= 10 if len(chunks[-1]) == 10: # This is a continuation line, so the 10th chunk of the # previous line must also be a continuation indicator. # Sometimes its first character is a `+`, but it's not # always present. Anyway, cut it off. chunks[-1][-1] = None c, _ = _chunk_line(next_line) c[0] = None chunks.append(c) elif len(chunks[-1]) == 10 and chunks[-1][-1] == " ": # automatic continuation: last chunk of previous line and first # chunk of current line are spaces c, _ = _chunk_line(next_line) if c[0] == " ": chunks[-1][9] = None c[0] = None chunks.append(c) else: # not a continuation break else: break # merge chunks according to large field format # large field format: 8 + 16 + 16 + 16 + 16 + 8 if chunks[0][0].startswith("GRID*"): new_chunks = [] for c in chunks: d = [c[0]] if len(c) > 1: d.append(c[1]) if len(c) > 2: d[-1] += c[2] if len(c) > 3: d.append(c[3]) if len(c) > 4: d[-1] += c[4] if len(c) > 5: d.append(c[5]) if len(c) > 6: d[-1] += c[6] if len(c) > 7: d.append(c[7]) if len(c) > 8: d[-1] += c[8] if len(c) > 9: d.append(c[9]) new_chunks.append(d) chunks = new_chunks # flatten chunks = [item for sublist in chunks for item in sublist] # remove None (continuation blocks) chunks = [chunk for chunk in chunks if chunk is not None] # strip chunks chunks = [chunk.strip() for chunk in chunks] keyword = chunks[0] # Points if keyword in ["GRID", "GRID*"]: point_id = int(chunks[1]) pref = chunks[2].strip() if len(pref) > 0: point_refs.append(int(pref)) points_id.append(point_id) points.append([_nastran_string_to_float(i) for i in chunks[3:6]]) # CellBlock elif keyword in nastran_to_meshio_type: cell_id = int(chunks[1]) cell_ref = chunks[2].strip() cell_ref = int(cell_ref) if len(cell_ref) > 0 else None if keyword in ["CBAR", "CBEAM", "CBUSH", "CBUSH1D", "CGAP"]: # Most Nastran 1D elements contain a third node (in the form of a node id or coordinates) to specify the local coordinate system: # https://docs.plm.automation.siemens.com/data_services/resources/nxnastran/10/help/en_US/tdocExt/pdf/QRG.pdf # For example, a CBAR line can be # ``` # CBAR 37 3 11.0 0.0 0.0 # ``` # where the last three floats specify the orientation vector. # This information is removed. cell = chunks[3:5] else: cell = chunks[3:] # remove empty chunks cell = [item for item in cell if item != ""] if cell is not None: add_cell(keyword, cell, cell_ref) # Convert to numpy arrays points = np.array(points) points_id = np.array(points_id, dtype=int) for k, (c, cid) in enumerate(zip(cells, cells_id)): cells[k] = CellBlock(c[0], np.array(c[1], dtype=int)) cells_id[k] = np.array(cid, dtype=int) # Convert to natural point ordering # https://stackoverflow.com/questions/16992713/translate-every-element-in-numpy-array-according-to-key points_id_dict = dict(zip(points_id, np.arange(len(points), dtype=int))) points_id_get = np.vectorize(points_id_dict.__getitem__) for k, c in enumerate(cells): cells[k] = CellBlock(c.type, points_id_get(c.data)) # Construct the mesh object mesh = Mesh(points, cells) mesh.points_id = points_id mesh.cells_id = cells_id if len(point_refs) > 0: mesh.point_data["nastran:ref"] = np.array(point_refs) if len(cell_refs) > 0: mesh.cell_data["nastran:ref"] = [np.array(i) for i in cell_refs] return mesh # There are two basic categories of input data formats in NX Nastran: # # - "Free" format data, in which the data fields are simply separated by # commas. This type of data is known as free field data. # # - "Fixed" format data, in which your data must be aligned in columns of # specific width. There are two subcategories of fixed format data that differ # based on the size of the fixed column width: # # - Small field format, in which a single line of data is divided into 10 # fields that can contain eight characters each. # # - Large field format, in which a single line of input is expanded into # two lines The first and last fields on each line are eight columns wide, # while the intermediate fields are sixteen columns wide. The large field # format is useful when you need greater numerical accuracy. # # See: https://docs.plm.automation.siemens.com/data_services/resources/nxnastran/10/help/en_US/tdocExt/pdf/User.pdf def write(filename, mesh, point_format="fixed-large", cell_format="fixed-small"): if point_format == "free": grid_fmt = "GRID,{:d},{:s},{:s},{:s},{:s}\n" float_fmt = _float_to_nastran_string elif point_format == "fixed-small": grid_fmt = "GRID {:<8d}{:<8s}{:>8s}{:>8s}{:>8s}\n" float_fmt = _float_rstrip elif point_format == "fixed-large": grid_fmt = "GRID* {:<16d}{:<16s}{:>16s}{:>16s}\n* {:>16s}\n" float_fmt = _float_to_nastran_string else: raise RuntimeError(f'unknown "{format}" format') if cell_format == "free": int_fmt, cell_info_fmt = "{:d}", "{:s},{:d},{:s}," sjoin = "," elif cell_format == "fixed-small": int_fmt, cell_info_fmt = "{:<8d}", "{:<8s}{:<8d}{:<8s}" sjoin, cchar = "", "+" nipl1, nipl2 = 6, 14 elif cell_format == "fixed-large": int_fmt, cell_info_fmt = "{:<16d}", "{:<8s}{:<16d}{:<16s}" sjoin, cchar = "", "*" nipl1, nipl2 = 2, 6 else: raise RuntimeError(f'unknown "{format}" format') if mesh.points.shape[1] == 2: warn( "Nastran requires 3D points, but 2D points given. " "Appending 0 third component." ) points = np.column_stack([mesh.points, np.zeros_like(mesh.points[:, 0])]) else: points = mesh.points with open_file(filename, "w") as f: f.write(f"$ Nastran file written by meshio v{__version__}\n") f.write("BEGIN BULK\n") # Points point_refs = mesh.point_data.get("nastran:ref", None) for point_id, x in enumerate(points): fx = [float_fmt(k) for k in x] pref = str(point_refs[point_id]) if point_refs is not None else "" string = grid_fmt.format(point_id + 1, pref, fx[0], fx[1], fx[2]) f.write(string) # CellBlock cell_id = 0 cell_refs = mesh.cell_data.get("nastran:ref", None) for ict, cell_block in enumerate(mesh.cells): cell_type = cell_block.type cells = cell_block.data nastran_type = meshio_to_nastran_type[cell_type] if cell_format.endswith("-large"): nastran_type += "*" if cell_refs is not None: cell_refs_t = cell_refs[ict] else: cell_ref = "" for ic, cell in enumerate(cells): if cell_refs is not None: cell_ref = str(int(cell_refs_t[ic])) cell_id += 1 cell_info = cell_info_fmt.format(nastran_type, cell_id, cell_ref) cell1 = cell + 1 cell1 = _convert_to_nastran_ordering(cell1, nastran_type) conn = sjoin.join(int_fmt.format(nid) for nid in cell1[:nipl1]) if len(cell1) > nipl1: if cell_format == "free": cflag1 = cflag3 = "" cflag2 = cflag4 = "+," else: cflag1 = cflag2 = f"{cchar}1{cell_id:<6x}" cflag3 = cflag4 = f"{cchar}2{cell_id:<6x}" f.write(cell_info + conn + cflag1 + "\n") conn = sjoin.join(int_fmt.format(nid) for nid in cell1[nipl1:nipl2]) if len(cell1) > nipl2: f.write(cflag2 + conn + cflag3 + "\n") conn = sjoin.join(int_fmt.format(nid) for nid in cell1[nipl2:]) f.write(cflag4 + conn + "\n") else: f.write(cflag2 + conn + "\n") else: f.write(cell_info + conn + "\n") f.write("ENDDATA\n") def _float_rstrip(x, n=8): return f"{x:f}".rstrip("0")[:n] def _float_to_nastran_string(value, length=16): """ From : Real numbers, including zero, must contain a decimal point. You can enter real numbers in a variety of formats. For example, the following are all acceptable versions of the real number, seven: ``` 7.0 .7E1 0.7+1 .70+1 7.E+0 70.-1 ``` This methods converts a float value into the corresponding string. Choose the variant with `E` to make the file less ambigious when edited by a human. (`5.-1` looks like 4.0, not 5.0e-1 = 0.5.) Examples: 1234.56789 --> "1.23456789E+3" -0.1234 --> "-1.234E-1" 3.1415926535897932 --> "3.14159265359E+0" """ out = np.format_float_scientific(value, exp_digits=1, precision=11).replace( "e", "E" ) assert len(out) <= 16 return out # The following is the manual float conversion. Keep it around for a while in case # we still need it. # aux = length - 2 # # sfmt = "{" + f":{length}s" + "}" # sfmt = "{" + ":s" + "}" # pv_fmt = "{" + f":{length}.{aux}e" + "}" # if value == 0.0: # return sfmt.format("0.") # python_value = pv_fmt.format(value) # -1.e-2 # svalue, sexponent = python_value.strip().split("e") # exponent = int(sexponent) # removes 0s # sign = "-" if abs(value) < 1.0 else "+" # # the exponent will be added later... # sexp2 = str(exponent).strip("-+") # value2 = float(svalue) # # the plus 1 is for the sign # len_sexp = len(sexp2) + 1 # leftover = length - len_sexp # leftover = leftover - 3 if value < 0 else leftover - 2 # fmt = "{" + f":1.{leftover:d}f" + "}" # svalue3 = fmt.format(value2) # svalue4 = svalue3.strip("0") # field = sfmt.format(svalue4 + sign + sexp2) # return field def _nastran_string_to_float(string): try: return float(string) except ValueError: string = string.strip() return float(string[0] + string[1:].replace("+", "e+").replace("-", "e-")) def _chunk_line(line: str) -> tuple[list[str], bool]: # remove terminal newline assert line[-1] == "\n" line = line[:-1] if "," in line: # free format return line.split(","), True # fixed format CHUNK_SIZE = 8 chunks = [line[i : CHUNK_SIZE + i] for i in range(0, len(line), CHUNK_SIZE)] return chunks, False def _convert_to_vtk_ordering(cell, nastran_type): if nastran_type in ["CTRAX6", "CTRIAX6"]: cell = [cell[i] for i in [0, 2, 4, 1, 3, 5]] elif nastran_type == "CHEXA_": cell = [ cell[i] for i in [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19, 12, 13, 14, 15, ] ] elif nastran_type == "CPENTA_": cell = [cell[i] for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14, 9, 10, 11]] return cell def _convert_to_nastran_ordering(cell, nastran_type): if nastran_type in ["CTRAX6", "CTRIAX6"]: cell = [cell[i] for i in [0, 3, 1, 4, 2, 5]] elif nastran_type == "CHEXA_": cell = [ cell[i] for i in [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 16, 17, 18, 19, 12, 13, 14, 15, ] ] elif nastran_type == "CPENTA_": cell = [cell[i] for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14, 9, 10, 11]] return cell register_format("nastran", [".bdf", ".fem", ".nas"], read, {"nastran": write}) src/meshio/netgen/000077500000000000000000000000001456244072500144225ustar00rootroot00000000000000src/meshio/netgen/__init__.py000066400000000000000000000000761456244072500165360ustar00rootroot00000000000000from ._netgen import read, write __all__ = ["read", "write"] src/meshio/netgen/_netgen.py000066400000000000000000000316541456244072500164240ustar00rootroot00000000000000""" I/O for Netgen mesh files . """ import numpy as np from ..__about__ import __version__ from .._common import warn from .._files import open_file from .._helpers import register_format from .._mesh import Mesh def _fast_forward_over_blank_lines(f): is_eof = False while True: line = f.readline() if not line: is_eof = True break line = line.strip() if len(line) > 0 and not line.startswith("#"): break return line, is_eof netgen_codims = {"materials": 0, "bcnames": 1, "cd2names": 2, "cd3names": 3} netgen0d_to_meshio_type = { 1: "vertex", } netgen1d_to_meshio_type = { 2: "line", } netgen2d_to_meshio_type = { 3: "triangle", 6: "triangle6", 4: "quad", 8: "quad8", } netgen3d_to_meshio_type = { 4: "tetra", 5: "pyramid", 6: "wedge", 8: "hexahedron", 10: "tetra10", 13: "pyramid13", 15: "wedge15", 20: "hexahedron20", } netgen_to_meshio_type = { 0: netgen0d_to_meshio_type, 1: netgen1d_to_meshio_type, 2: netgen2d_to_meshio_type, 3: netgen3d_to_meshio_type, } netgen_to_meshio_pmap = { "vertex": [0], "line": [0, 1], "triangle": list(range(3)), "triangle6": [0, 1, 2, 5, 3, 4], "quad": list(range(4)), "quad8": [0, 1, 2, 3, 4, 7, 5, 6], "tetra": [0, 2, 1, 3], "tetra10": [0, 2, 1, 3, 5, 7, 4, 6, 9, 8], "pyramid": [0, 3, 2, 1, 4], "pyramid13": [0, 3, 2, 1, 4, 7, 6, 8, 5, 9, 12, 11, 10], "wedge": [0, 2, 1, 3, 5, 4], "wedge15": [0, 2, 1, 3, 5, 4, 7, 8, 6, 13, 14, 12, 9, 11, 10], "hexahedron": [0, 3, 2, 1, 4, 7, 6, 5], "hexahedron20": [ 0, 3, 2, 1, 4, 7, 6, 5, 10, 9, 11, 8, 16, 19, 18, 17, 14, 13, 15, 12, ], } meshio_to_netgen_pmap = {} for t, pmap in netgen_to_meshio_pmap.items(): n = len(pmap) ipmap = list(range(n)) for i in range(n): ipmap[pmap[i]] = i meshio_to_netgen_pmap[t] = ipmap def read(filename): if str(filename).endswith(".vol.gz"): import gzip with gzip.open(filename, "rt") as f: return read_buffer(f) with open_file(filename, "r") as f: return read_buffer(f) def _read_cells(f, netgen_cell_type, cells, cells_index, skip_every_other_line=False): if netgen_cell_type == "pointelements": dim = 0 nump = 1 pi0 = 0 i_index = 1 elif netgen_cell_type.startswith("edgesegments"): dim = 1 nump = 2 pi0 = 2 i_index = 0 elif netgen_cell_type.startswith("surfaceelements"): dim = 2 pi0 = 5 i_index = 1 elif netgen_cell_type == "volumeelements": dim = 3 pi0 = 2 i_index = 0 else: raise ValueError(f"Unknown Netgen cell section '{netgen_cell_type}'") num_cells = int(f.readline()) tmap = netgen_to_meshio_type[dim] for _ in range(num_cells): line, _ = _fast_forward_over_blank_lines(f) data = list(filter(None, line.split(" "))) index = int(data[i_index]) if dim == 2: nump = int(data[4]) elif dim == 3: nump = int(data[1]) pi = list(map(int, data[pi0 : pi0 + nump])) t = tmap[nump] if len(cells) == 0 or t != cells[-1][0]: cells.append((t, [])) cells_index.append([]) cells[-1][1].append(pi) cells_index[-1].append(index) if skip_every_other_line: line, _ = _fast_forward_over_blank_lines(f) def _write_cells(f, cell_block, index=None): if len(cell_block) == 0: return pmap = np.array(meshio_to_netgen_pmap[cell_block.type]) post_data = [] pre_data = [] i_index = 0 if cell_block.dim == 0: post_data = [1] i_index = 1 elif cell_block.dim == 1: pre_data = [1, 0] post_data = [-1, -1, 0, 0, 1, 0, 1, 0] elif cell_block.dim == 2: pre_data = [1, 1, 0, 0, len(pmap)] i_index = 1 elif cell_block.dim == 3: pre_data = [1, len(pmap)] else: raise ValueError(f"Invalid cell dimension: {cell_block.dim}") col1 = len(pre_data) col2 = col1 + len(pmap) col3 = col2 + len(post_data) pi = np.zeros((len(cell_block), col3), dtype=np.int32) pi[:, :col1] = np.repeat([pre_data], len(cell_block), axis=0) pi[:, col1:col2] = cell_block.data[:, pmap] + 1 pi[:, col2:] = np.repeat([post_data], len(cell_block), axis=0) if index is not None: pi[:, i_index] = index np.savetxt(f, pi, "%i") def _skip_block(f): n = int(f.readline()) for _ in range(n): f.readline() def _write_codim_domain_data(f, mesh, cells_index, dim, codim): # assume format as read from gmsh 4.1 files data = {} for name, val in mesh.field_data.items(): if val[1] == dim - codim: data[val[0]] = name # set generic default names (is this appropriate/useful?) if len(data) == 0: indices = set() for cell_block, index in zip(mesh.cells, cells_index): if index is None: continue if cell_block.dim == dim - codim: indices = indices.union(set(index)) for idx in indices: data[idx] = f"cd{codim:d}_{idx:d}" if len(data) == 0: return codim_tag = [kk for kk, vv in netgen_codims.items() if vv == codim][0] f.write(f"\n{codim_tag:s}\n") ncd = max(data.keys()) f.write(f"{ncd:d}\n") for idx in range(1, ncd + 1): f.write("{:d} {:s}\n".format(idx, data.get(idx, ""))) def read_buffer(f): points = [] cells = [] cells_index = [] field_data = {} identifications = None identificationtypes = None have_edgesegmentsgi2_in_two_lines = False line, is_eof = _fast_forward_over_blank_lines(f) if line != "mesh3d": raise RuntimeError("Not a valid Netgen mesh") while True: line, is_eof = _fast_forward_over_blank_lines(f) if is_eof: break elif line == "dimension": dimension = int(f.readline()) elif line == "geomtype": geomtype = int(f.readline()) if geomtype not in [0, 1, 10, 11, 12, 13]: warn(f"Unknown geomtype in Netgen mesh: {geomtype}") elif line == "points": num_points = int(f.readline()) if num_points > 0: points = np.loadtxt(f, max_rows=num_points) if dimension != 3: points = points[:, :dimension] elif line in [ "pointelements", "edgesegments", "edgesegmentsgi", "edgesegmentsgi2", "surfaceelements", "surfaceelementsgi", "surfaceelementsuv", "volumeelements", ]: _read_cells(f, line, cells, cells_index, have_edgesegmentsgi2_in_two_lines) elif line == "endmesh": break elif line.split() == ["surf1", "surf2", "p1", "p2"]: # if this line is present, the edgesegmentsgi2 info is split in two lines per data set have_edgesegmentsgi2_in_two_lines = True elif line in netgen_codims.keys(): edim = dimension - netgen_codims[line] num_entries = int(f.readline()) for _ in range(num_entries): line = f.readline().split() if len(line) != 2: continue idx, name = line field_data[name] = [int(idx), edim] elif line == "identifications": num_entries = int(f.readline()) if num_entries > 0: identifications = np.loadtxt( f, max_rows=num_entries, dtype=int ).reshape(num_entries, 3) elif line == "identificationtypes": num_entries = int(f.readline()) if num_entries > 0: identificationtypes = np.loadtxt(f, max_rows=1, dtype=int).reshape( 1, num_entries ) elif line in [ "face_colours", "singular_edge_left", "singular_edge_right", "singular_face_inside", "singular_face_outside", "singular_points", ]: _skip_block(f) else: raise RuntimeError(f"Unknown Netgen mesh token: {line}") # convert to numpy arrays # subtract one (netgen counts 1-based) # apply permutation of vertex numbers for k, (t, data) in enumerate(cells): pmap = netgen_to_meshio_pmap[t] d = np.array(data, dtype=np.uint32) d[:, :] = d[:, pmap] - 1 cells[k] = (t, d) # currently, there is no better place for identification data kwargs = {} if identifications is not None: kwargs["info"] = { "netgen:identifications": identifications, "netgen:identificationtypes": identificationtypes, } mesh = Mesh( points, cells, cell_data={"netgen:index": cells_index}, field_data=field_data, **kwargs, ) return mesh def write(filename, mesh, float_fmt=".16e"): if str(filename).endswith(".vol.gz"): import gzip with gzip.open(filename, "wt") as f: write_buffer(f, mesh, float_fmt) return with open_file(filename, "w") as f: write_buffer(f, mesh, float_fmt) def write_buffer(f, mesh, float_fmt): _, dimension = mesh.points.shape cells_per_dim = [0, 0, 0, 0] # Netgen can store one cell_index, i.e., integer cell data. Pick one in # mesh.cell_data, and prefer "netgen:index" if present. Unfortunately, netgen cannot # store the name of the data; when reading, it will always be "netgen:index". # See also . if "netgen:index" in mesh.cell_data: cells_index = mesh.cell_data["netgen:index"] else: # any other integer cell data? cells_index = None for values in mesh.cell_data.values(): if np.issubdtype(values[0].dtype, np.integer): cells_index = values break if cells_index is None: cells_index = [None] * len(mesh.cells) for cell_block in mesh.cells: cells_per_dim[cell_block.dim] += len(cell_block) f.write(f"# Generated by meshio {__version__}\n") f.write("mesh3d\n\n") f.write("dimension\n") f.write(f"{dimension}\n\n") f.write("geomtype\n") f.write("0\n") f.write("\n# surfnr bcnr domin domout np p1 p2 p3\n") f.write("surfaceelements\n") f.write(f"{cells_per_dim[2]}\n") for cell_block, index in zip(mesh.cells, cells_index): if cell_block.dim == 2: _write_cells(f, cell_block, index) f.write("\n# matnr np p1 p2 p3 p4\n") f.write("volumeelements\n") f.write(f"{cells_per_dim[3]}\n") for cell_block, index in zip(mesh.cells, cells_index): if cell_block.dim == 3: _write_cells(f, cell_block, index) f.write( "\n# surfid 0 p1 p2 trignum1 trignum2 domin/surfnr1 domout/surfnr2 ednr1 dist1 ednr2 dist2\n", ) f.write("edgesegmentsgi2\n") f.write(f"{cells_per_dim[1]}\n") for cell_block, index in zip(mesh.cells, cells_index): if cell_block.dim == 1: _write_cells(f, cell_block, index) f.write("\n# X Y Z\n") f.write("points\n") f.write(f"{len(mesh.points)}\n") points = mesh.points if dimension != 3: points = np.hstack( (points, np.zeros((points.shape[0], 3 - dimension), dtype=points.dtype)) ) np.savetxt(f, points, "%" + float_fmt) f.write("\n# pnum index\n") f.write("pointelements\n") f.write(f"{cells_per_dim[0]}\n") for cell_block, index in zip(mesh.cells, cells_index): if cell_block.dim == 0: _write_cells(f, cell_block, index) # currently, there is no better place for identification data if isinstance(mesh.info, dict): identifications = mesh.info.get("netgen:identifications") identificationtypes = mesh.info.get("netgen:identificationtypes") if identifications is not None and identificationtypes is not None: f.write("\nidentifications\n") f.write(f"{identifications.shape[0]}\n") np.savetxt(f, identifications, "%d") f.write("\nidentificationtypes\n") f.write(f"{identificationtypes.size}\n") np.savetxt( f, identificationtypes.reshape(1, identificationtypes.size), "%d" ) for codim in range(dimension + 1): _write_codim_domain_data(f, mesh, cells_index, dimension, codim) f.write("\nendmesh\n") register_format("netgen", [".vol", ".vol.gz"], read, {"netgen": write}) src/meshio/neuroglancer/000077500000000000000000000000001456244072500156265ustar00rootroot00000000000000src/meshio/neuroglancer/__init__.py000066400000000000000000000001041456244072500177320ustar00rootroot00000000000000from ._neuroglancer import read, write __all__ = ["read", "write"] src/meshio/neuroglancer/_neuroglancer.py000066400000000000000000000054371456244072500210340ustar00rootroot00000000000000""" Neuroglancer format, used in large-scale neuropil segmentation data. Adapted from https://github.com/HumanBrainProject/neuroglancer-scripts/blob/1fcabb613a715ba17c65d52596dec3d687ca3318/src/neuroglancer_scripts/mesh.py (MIT license) """ import struct import numpy as np from .._common import warn from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh def write(filename, mesh): with open_file(filename, "wb") as f: write_buffer(f, mesh) def write_buffer(f, mesh): """Store a mesh in Neuroglancer pre-computed format. :param file: a file-like object opened in binary mode (its ``write`` method will be called with :class:`bytes` objects). :param meshio.Mesh mesh: Mesh object to write """ vertices = np.asarray(mesh.points, " num_vertices): raise ReadError("The mesh references nonexistent vertices") return Mesh(vertices, [CellBlock("triangle", triangles)]) register_format("neuroglancer", [], read, {"neuroglancer": write}) src/meshio/obj/000077500000000000000000000000001456244072500137145ustar00rootroot00000000000000src/meshio/obj/__init__.py000066400000000000000000000000731456244072500160250ustar00rootroot00000000000000from ._obj import read, write __all__ = ["read", "write"] src/meshio/obj/_obj.py000066400000000000000000000100171456244072500151760ustar00rootroot00000000000000""" I/O for the Wavefront .obj file format, cf. . """ import datetime import numpy as np from ..__about__ import __version__ from .._exceptions import WriteError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh def read(filename): with open_file(filename, "r") as f: mesh = read_buffer(f) return mesh def read_buffer(f): points = [] vertex_normals = [] texture_coords = [] face_groups = [] face_group_ids = [] face_group_id = -1 while True: line = f.readline() if not line: # EOF break strip = line.strip() if len(strip) == 0 or strip[0] == "#": continue split = strip.split() if split[0] == "v": points.append([float(item) for item in split[1:]]) elif split[0] == "vn": vertex_normals.append([float(item) for item in split[1:]]) elif split[0] == "vt": texture_coords.append([float(item) for item in split[1:]]) elif split[0] == "s": # "s 1" or "s off" controls smooth shading pass elif split[0] == "f": dat = [int(item.split("/")[0]) for item in split[1:]] if len(face_groups) == 0 or ( len(face_groups[-1]) > 0 and len(face_groups[-1][-1]) != len(dat) ): face_groups.append([]) face_group_ids.append([]) face_groups[-1].append(dat) face_group_ids[-1].append(face_group_id) elif split[0] == "g": # new group face_groups.append([]) face_group_ids.append([]) face_group_id += 1 else: # who knows pass # There may be empty groups, too. # Remove them. face_groups = [f for f in face_groups if len(f) > 0] face_group_ids = [g for g in face_group_ids if len(g) > 0] points = np.array(points) texture_coords = np.array(texture_coords) vertex_normals = np.array(vertex_normals) point_data = {} if len(texture_coords) > 0: point_data["obj:vt"] = texture_coords if len(vertex_normals) > 0: point_data["obj:vn"] = vertex_normals # convert to numpy arrays face_groups = [np.array(f) for f in face_groups] cell_data = {"obj:group_ids": []} cells = [] for f, gid in zip(face_groups, face_group_ids): if f.shape[1] == 3: cells.append(CellBlock("triangle", f - 1)) elif f.shape[1] == 4: cells.append(CellBlock("quad", f - 1)) else: cells.append(CellBlock("polygon", f - 1)) cell_data["obj:group_ids"].append(gid) return Mesh(points, cells, point_data=point_data, cell_data=cell_data) def write(filename, mesh): for c in mesh.cells: if c.type not in ["triangle", "quad", "polygon"]: raise WriteError( "Wavefront .obj files can only contain triangle or quad cells." ) with open_file(filename, "w") as f: f.write( "# Created by meshio v{}, {}\n".format( __version__, datetime.datetime.now().isoformat() ) ) for p in mesh.points: f.write(f"v {p[0]} {p[1]} {p[2]}\n") if "obj:vn" in mesh.point_data: dat = mesh.point_data["obj:vn"] fmt = "vn " + " ".join(["{}"] * dat.shape[1]) + "\n" for vn in dat: f.write(fmt.format(*vn)) if "obj:vt" in mesh.point_data: dat = mesh.point_data["obj:vt"] fmt = "vt " + " ".join(["{}"] * dat.shape[1]) + "\n" for vt in dat: f.write(fmt.format(*vt)) for cell_block in mesh.cells: fmt = "f " + " ".join(["{}"] * cell_block.data.shape[1]) + "\n" for c in cell_block.data: f.write(fmt.format(*(c + 1))) register_format("obj", [".obj"], read, {"obj": write}) src/meshio/off/000077500000000000000000000000001456244072500137145ustar00rootroot00000000000000src/meshio/off/__init__.py000066400000000000000000000000731456244072500160250ustar00rootroot00000000000000from ._off import read, write __all__ = ["read", "write"] src/meshio/off/_off.py000066400000000000000000000054331456244072500152040ustar00rootroot00000000000000""" I/O for the OFF surface format, cf. , . """ import numpy as np from .._common import warn from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh def read(filename): with open_file(filename) as f: points, cells = read_buffer(f) return Mesh(points, cells) def read_buffer(f): # assert that the first line reads `OFF` line = f.readline() if isinstance(line, (bytes, bytearray)): raise ReadError("Expected text buffer, not bytes.") if line.strip() != "OFF": raise ReadError("Expected the first line to be `OFF`.") # fast forward to the next significant line while True: line = f.readline().strip() if line and line[0] != "#": break # This next line contains: # num_verts, num_faces, _ = line.split(" ") num_verts = int(num_verts) num_faces = int(num_faces) verts = np.fromfile(f, dtype=float, count=3 * num_verts, sep=" ").reshape( num_verts, 3 ) data = np.fromfile(f, dtype=int, count=4 * num_faces, sep=" ").reshape(num_faces, 4) if not np.all(data[:, 0] == 3): raise ReadError("Can only read triangular faces") cells = [CellBlock("triangle", data[:, 1:])] return verts, cells def write(filename, mesh): if mesh.points.shape[1] == 2: warn( "OFF requires 3D points, but 2D points given. " "Appending 0 as third component." ) points = np.column_stack([mesh.points, np.zeros_like(mesh.points[:, 0])]) else: points = mesh.points skip = [c for c in mesh.cells if c.type != "triangle"] if skip: string = ", ".join(item.type for item in skip) warn(f"OFF only supports triangle cells. Skipping {string}.") tri = mesh.get_cells_type("triangle") with open(filename, "wb") as fh: fh.write(b"OFF\n") fh.write(b"# Created by meshio\n\n") # counts c = f"{mesh.points.shape[0]} {tri.shape[0]} {0}\n\n" fh.write(c.encode()) # vertices # np.savetxt(fh, mesh.points, "%r") # slower fmt = " ".join(["{}"] * points.shape[1]) out = "\n".join([fmt.format(*row) for row in points]) + "\n" fh.write(out.encode()) # triangles out = np.column_stack([np.full(tri.shape[0], 3, dtype=tri.dtype), tri]) # savetxt is slower # np.savetxt(fh, out, "%d %d %d %d") fmt = " ".join(["{}"] * out.shape[1]) out = "\n".join([fmt.format(*row) for row in out]) + "\n" fh.write(out.encode()) register_format("off", [".off"], read, {"off": write}) src/meshio/permas/000077500000000000000000000000001456244072500144315ustar00rootroot00000000000000src/meshio/permas/__init__.py000066400000000000000000000000761456244072500165450ustar00rootroot00000000000000from ._permas import read, write __all__ = ["read", "write"] src/meshio/permas/_permas.py000066400000000000000000000211361456244072500164340ustar00rootroot00000000000000""" I/O for PERMAS dat files. """ import numpy as np from ..__about__ import __version__ from .._common import warn from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh permas_to_meshio_type = { "PLOT1": "vertex", "PLOTL2": "line", "FLA2": "line", "FLA3": "line3", "PLOTL3": "line3", "BECOS": "line", "BECOC": "line", "BETAC": "line", "BECOP": "line", "BETOP": "line", "BEAM2": "line", "FSCPIPE2": "line", "LOADA4": "quad", "PLOTA4": "quad", "QUAD4": "quad", "QUAD4S": "quad", "QUAMS4": "quad", "SHELL4": "quad", "PLOTA8": "quad8", "LOADA8": "quad8", "QUAMS8": "quad8", "PLOTA9": "quad9", "LOADA9": "quad9", "QUAMS9": "quad9", "PLOTA3": "triangle", "SHELL3": "triangle", "TRIA3": "triangle", "TRIA3K": "triangle", "TRIA3S": "triangle", "TRIMS3": "triangle", "LOADA6": "triangle6", "TRIMS6": "triangle6", "HEXE8": "hexahedron", "HEXFO8": "hexahedron", "HEXE20": "hexahedron20", "HEXE27": "hexahedron27", "TET4": "tetra", "TET10": "tetra10", "PYRA5": "pyramid", "PENTA6": "wedge", "PENTA15": "wedge15", } meshio_to_permas_type = {v: k for k, v in permas_to_meshio_type.items()} def read(filename): """Reads a PERMAS dat file.""" with open_file(filename, "r") as f: out = read_buffer(f) return out def read_buffer(f): # Initialize the optional data fields cells = [] nsets = {} elsets = {} field_data = {} cell_data = {} point_data = {} while True: line = f.readline() if not line: # EOF break # Comments if line.startswith("!"): continue keyword = line.strip("$").upper() if keyword.startswith("COOR"): points, point_gids = _read_nodes(f) elif keyword.startswith("ELEMENT"): key, idx = _read_cells(f, keyword, point_gids) cells.append(CellBlock(key, idx)) elif keyword.startswith("NSET"): params_map = get_param_map(keyword, required_keys=["NSET"]) setids = read_set(f, params_map) name = params_map["NSET"] if name not in nsets: nsets[name] = [] nsets[name].append(setids) elif keyword.startswith("ESET"): params_map = get_param_map(keyword, required_keys=["ESET"]) setids = read_set(f, params_map) name = params_map["ESET"] if name not in elsets: elsets[name] = [] elsets[name].append(setids) else: # There are just too many PERMAS keywords to explicitly skip them. pass return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data ) def _read_nodes(f): points = [] point_gids = {} index = 0 while True: last_pos = f.tell() line = f.readline() if line.startswith("!"): break if line.startswith("$"): break entries = line.strip().split(" ") gid, x = entries[0], entries[1:] point_gids[int(gid)] = index points.append([float(xx) for xx in x]) index += 1 f.seek(last_pos) return np.array(points, dtype=float), point_gids def _read_cells(f, line0, point_gids): sline = line0.split(" ")[1:] etype_sline = sline[0] if "TYPE" not in etype_sline: raise ReadError(etype_sline) etype = etype_sline.split("=")[1].strip() if etype not in permas_to_meshio_type: raise ReadError(f"Element type not available: {etype}") cell_type = permas_to_meshio_type[etype] cells, idx = [], [] while True: last_pos = f.tell() line = f.readline() if line.startswith("$") or line == "": break line = line.strip() # the first item is just a running index idx += [point_gids[int(k)] for k in filter(None, line.split(" ")[1:])] if not line.endswith("!"): cells.append(idx) idx = [] f.seek(last_pos) return cell_type, np.array(cells) def get_param_map(word, required_keys=None): """ get the optional arguments on a line Example ------- >>> iline = 0 >>> word = 'elset,instance=dummy2,generate' >>> params = get_param_map(iline, word, required_keys=['instance']) params = { 'elset' : None, 'instance' : 'dummy2, 'generate' : None, } """ if required_keys is None: required_keys = [] words = word.split(",") param_map = {} for wordi in words: if "=" not in wordi: key = wordi.strip() value = None else: sword = wordi.split("=") if len(sword) != 2: raise ReadError(sword) key = sword[0].strip() value = sword[1].strip() param_map[key] = value msg = "" for key in required_keys: if key not in param_map: msg += f"{key} not found in {word}\n" if msg: raise RuntimeError(msg) return param_map def read_set(f, params_map): set_ids = [] while True: last_pos = f.tell() line = f.readline() if line.startswith("$"): break set_ids += [int(k) for k in line.strip().strip(" ").split(" ")] f.seek(last_pos) if "generate" in params_map: if len(set_ids) != 3: raise ReadError(set_ids) set_ids = np.arange(set_ids[0], set_ids[1], set_ids[2]) else: try: set_ids = np.unique(np.array(set_ids, dtype="int32")) except ValueError: raise return set_ids def write(filename, mesh): if mesh.points.shape[1] == 2: warn( "PERMAS requires 3D points, but 2D points given. " "Appending 0 third component." ) points = np.column_stack([mesh.points, np.zeros_like(mesh.points[:, 0])]) else: points = mesh.points with open_file(filename, "wt") as f: f.write("!PERMAS DataFile Version 18.0\n") f.write(f"!written by meshio v{__version__}\n") f.write("$ENTER COMPONENT NAME=DFLT_COMP\n") f.write("$STRUCTURE\n") f.write("$COOR\n") for k, x in enumerate(points): f.write(f"{k + 1} {x[0]} {x[1]} {x[2]}\n") eid = 0 tria6_order = [0, 3, 1, 4, 2, 5] tet10_order = [0, 4, 1, 5, 2, 6, 7, 8, 9, 3] quad9_order = [0, 4, 1, 7, 8, 5, 3, 6, 2] wedge15_order = [0, 6, 1, 7, 2, 8, 9, 10, 11, 3, 12, 4, 13, 5, 14] for cell_block in mesh.cells: node_idcs = cell_block.data f.write("!\n") f.write("$ELEMENT TYPE=" + meshio_to_permas_type[cell_block.type] + "\n") if cell_block.type == "tetra10": for row in node_idcs: eid += 1 mylist = row.tolist() mylist = [mylist[i] for i in tet10_order] nids_strs = (str(nid + 1) for nid in mylist) f.write(str(eid) + " " + " ".join(nids_strs) + "\n") elif cell_block.type == "triangle6": for row in node_idcs: eid += 1 mylist = row.tolist() mylist = [mylist[i] for i in tria6_order] nids_strs = (str(nid + 1) for nid in mylist) f.write(str(eid) + " " + " ".join(nids_strs) + "\n") elif cell_block.type == "quad9": for row in node_idcs: eid += 1 mylist = row.tolist() mylist = [mylist[i] for i in quad9_order] nids_strs = (str(nid + 1) for nid in mylist) f.write(str(eid) + " " + " ".join(nids_strs) + "\n") elif cell_block.type == "wedge15": for row in node_idcs: eid += 1 mylist = row.tolist() mylist = [mylist[i] for i in wedge15_order] nids_strs = (str(nid + 1) for nid in mylist) f.write(str(eid) + " " + " ".join(nids_strs) + "\n") else: for row in node_idcs: eid += 1 nids_strs = (str(nid + 1) for nid in row.tolist()) f.write(str(eid) + " " + " ".join(nids_strs) + "\n") f.write("$END STRUCTURE\n") f.write("$EXIT COMPONENT\n") f.write("$FIN\n") register_format( "permas", [".post", ".post.gz", ".dato", ".dato.gz"], read, {"permas": write} ) src/meshio/ply/000077500000000000000000000000001456244072500137465ustar00rootroot00000000000000src/meshio/ply/__init__.py000066400000000000000000000000731456244072500160570ustar00rootroot00000000000000from ._ply import read, write __all__ = ["read", "write"] src/meshio/ply/_ply.py000066400000000000000000000422241456244072500152670ustar00rootroot00000000000000""" I/O for the PLY format, cf. . . """ import collections import datetime import re import sys import numpy as np from ..__about__ import __version__ from .._common import warn from .._exceptions import ReadError, WriteError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh # Reference dtypes ply_to_numpy_dtype = { # [u]char is often used as [u]int, e.g., from Wikipedia: # > The word 'list' indicates that the data is a list of values, the first of which # > is the number of entries in the list (represented as a 'uchar' in this case). "char": np.int8, "uchar": np.uint8, "short": np.int16, "ushort": np.uint16, "int": np.int32, "int8": np.int8, "int32": np.int32, "int64": np.int64, "uint": np.uint32, "uint8": np.uint8, "uint16": np.uint16, "uint32": np.uint32, "uint64": np.uint64, "float": np.float32, "float32": np.float32, "float64": np.float64, "double": np.float64, } numpy_to_ply_dtype = {np.dtype(v): k for k, v in ply_to_numpy_dtype.items()} def cell_type_from_count(count): if count == 1: return "vertex" elif count == 2: return "line" elif count == 3: return "triangle" elif count == 4: return "quad" return "polygon" def read(filename): with open_file(filename, "rb") as f: mesh = read_buffer(f) return mesh def _next_line(f): # fast forward to the next significant line while True: line = f.readline().decode().strip() if line and line[:7] != "comment": break return line def read_buffer(f): # assert that the first line reads `ply` line = f.readline().decode().strip() if line != "ply": raise ReadError("Expected ply") line = _next_line(f) endianness = None if line == "format ascii 1.0": is_binary = False elif line == "format binary_big_endian 1.0": is_binary = True endianness = ">" else: if line != "format binary_little_endian 1.0": raise ReadError() is_binary = True endianness = "<" # read header line = _next_line(f) num_verts = 0 num_cells = 0 point_data_formats = [] point_data_names = [] cell_data_names = [] cell_data_dtypes = [] while line != "end_header": m_vert = re.match("element vertex (\\d+)", line) m_face = re.match("element face (\\d+)", line) if line[:8] == "obj_info": line = _next_line(f) elif m_vert is not None: num_verts = int(m_vert.groups()[0]) # read point data line = _next_line(f) while line[:8] == "property": m = re.match("property (.+) (.+)", line) assert m is not None point_data_formats.append(m.groups()[0]) point_data_names.append(m.groups()[1]) line = _next_line(f) elif m_face is not None: num_cells = int(m_face.groups()[0]) if num_cells < 0: raise ReadError(f"Expected positive num_cells (got `{num_cells}`.") # read property lists line = _next_line(f) # read cell data while line[:8] == "property": if line[:13] == "property list": m = re.match("property list (.+) (.+) (.+)", line) assert m is not None cell_data_dtypes.append(tuple(m.groups()[:-1])) else: m = re.match("property (.+) (.+)", line) assert m is not None cell_data_dtypes.append(m.groups()[0]) cell_data_names.append(m.groups()[-1]) line = _next_line(f) else: raise ReadError( "Expected `element vertex` or `element face` or `obj_info`, " f"got `{line}`" ) if is_binary: mesh = _read_binary( f, endianness, point_data_names, point_data_formats, num_verts, num_cells, cell_data_names, cell_data_dtypes, ) else: mesh = _read_ascii( f, point_data_names, point_data_formats, num_verts, num_cells, cell_data_names, cell_data_dtypes, ) return mesh def _read_ascii( f, point_data_names, point_data_formats, num_verts, num_cells, cell_data_names, cell_dtypes, ): assert len(cell_data_names) == len(cell_dtypes) # assert that all formats are the same # Now read the data dtype = np.dtype( [ (name, ply_to_numpy_dtype[fmt]) for name, fmt in zip(point_data_names, point_data_formats) ] ) pd = np.genfromtxt(f, max_rows=num_verts, dtype=dtype) # split off coordinate data and additional point data verts = [] k = 0 if point_data_names[0] == "x": verts.append(pd["x"]) k += 1 if point_data_names[1] == "y": verts.append(pd["y"]) k += 1 if point_data_names[2] == "z": verts.append(pd["z"]) k += 1 verts = np.column_stack(verts) point_data = { point_data_names[i]: pd[point_data_names[i]] for i in range(k, len(point_data_names)) } cell_data = {} cell_blocks = [] for k in range(num_cells): line = f.readline().decode().strip() data = line.split() if k == 0: # initialize the cell data arrays i = 0 cell_data = {} for name, dtype in zip(cell_data_names, cell_dtypes): if name == "vertex_indices": n = int(data[i]) i += n + 1 else: cell_data[name] = collections.defaultdict(list) i += 1 # go over the line i = 0 n = None for name, dtype in zip(cell_data_names, cell_dtypes): if name == "vertex_indices": idx_dtype, value_dtype = dtype n = ply_to_numpy_dtype[idx_dtype](data[i]) dtype = ply_to_numpy_dtype[value_dtype] idx = dtype(data[i + 1 : i + n + 1]) if len(cell_blocks) == 0 or len(cell_blocks[-1][1][-1]) != n: cell_blocks.append((cell_type_from_count(n), [idx])) else: cell_blocks[-1][1].append(idx) i += n + 1 else: dtype = ply_to_numpy_dtype[dtype] # use n from vertex_indices assert n is not None cell_data[name][n] += [dtype(data[j]) for j in range(i, i + 1)] i += 1 cell_data = { key: [np.array(v) for v in value.values()] for key, value in cell_data.items() } return Mesh(verts, cell_blocks, point_data=point_data, cell_data=cell_data) def _read_binary( f, endianness, point_data_names, formats, num_verts, num_cells, cell_data_names, cell_data_dtypes, ): ply_to_numpy_dtype_string = { "uchar": "i1", "uint": "u4", "uint8": "u1", "uint16": "u2", "uint32": "u4", "uint64": "u8", "int": "i4", "int8": "i1", "int32": "i4", "int64": "i8", "float": "f4", "float32": "f4", "double": "f8", } # read point data dtype = [ (name, endianness + ply_to_numpy_dtype_string[fmt]) for name, fmt in zip(point_data_names, formats) ] point_data = np.frombuffer( f.read(num_verts * np.dtype(dtype).itemsize), dtype=dtype ) verts = np.column_stack([point_data["x"], point_data["y"], point_data["z"]]) point_data = { name: point_data[name] for name in point_data_names if name not in ["x", "y", "z"] } # Convert strings to proper numpy dtypes dts = [ ( ( endianness + ply_to_numpy_dtype_string[dtype[0]], endianness + ply_to_numpy_dtype_string[dtype[1]], ) if isinstance(dtype, tuple) else endianness + ply_to_numpy_dtype_string[dtype] ) for dtype in cell_data_dtypes ] # memoryviews can be sliced and passed around without copying. However, the # `bytearray()` call here redundantly copies so that the final output arrays # are writeable. buffer = memoryview(bytearray(f.read())) buffer_position = 0 cell_data = {} for name, dt in zip(cell_data_names, dts): if isinstance(dt, tuple): buffer_increment, cell_data[name] = _read_binary_list( buffer[buffer_position:], dt[0], dt[1], num_cells, endianness ) else: buffer_increment = np.dtype(dt).itemsize cell_data[name] = np.frombuffer( buffer[buffer_position : buffer_position + buffer_increment], dtype=dt )[0] buffer_position += buffer_increment cells = cell_data.pop("vertex_indices", []) return Mesh(verts, cells, point_data=point_data, cell_data=cell_data) def _read_binary_list(buffer, count_dtype, data_dtype, num_cells, endianness): """Parse a ply ragged list into a :class:`CellBlock` for each change in row length. The only way to know how many bytes the list takes up is to parse it. Hence this function also returns the number of bytes consumed. """ count_dtype, data_dtype = np.dtype(count_dtype), np.dtype(data_dtype) count_itemsize = count_dtype.itemsize data_itemsize = data_dtype.itemsize byteorder = "little" if endianness == "<" else "big" # Firstly, walk the buffer to extract all start and end ids (in bytes) of # each row into `byte_starts_ends`. Using `np.fromiter(generator)` is # 2-3x faster than list comprehension or manually populating an array with # a for loop. This is still very much the bottleneck - might be worth # ctype-ing in future? def parse_ragged(start, num_cells): at = start yield at for _ in range(num_cells): count = int.from_bytes(buffer[at : at + count_itemsize], byteorder) at += count * data_itemsize + count_itemsize yield at # Row `i` is given by `buffer[byte_starts_ends[i]: byte_starts_ends[i+1]]`. byte_starts_ends = np.fromiter(parse_ragged(0, num_cells), np.intp, num_cells + 1) # Next, find where the row length changes and list the (start, end) row ids # of each homogeneous block into `block_bounds`. row_lengths = np.diff(byte_starts_ends) count_changed_ids = np.nonzero(np.diff(row_lengths))[0] + 1 block_bounds = [] start = 0 for end in count_changed_ids: block_bounds.append((start, end)) start = end block_bounds.append((start, len(byte_starts_ends) - 1)) # Finally, parse each homogeneous block. Constructing an appropriate # `block_dtype` to include the initial counts in each row avoids any # wasteful copy operations. blocks = [] for start, end in block_bounds: if start == end: # This should only happen if the element was empty to begin with. continue block_buffer = buffer[byte_starts_ends[start] : byte_starts_ends[end]] cells_per_row = (row_lengths[start] - count_itemsize) // data_itemsize block_dtype = np.dtype( [("count", count_dtype), ("data", data_dtype * cells_per_row)] ) cells = np.frombuffer(block_buffer, dtype=block_dtype)["data"] cell_type = cell_type_from_count(cells.shape[1]) blocks.append(CellBlock(cell_type, cells)) return byte_starts_ends[-1], blocks def write(filename, mesh: Mesh, binary: bool = True): # noqa: C901 with open_file(filename, "wb") as fh: fh.write(b"ply\n") if binary: fh.write(f"format binary_{sys.byteorder}_endian 1.0\n".encode()) else: fh.write(b"format ascii 1.0\n") now = datetime.datetime.now().isoformat() fh.write(f"comment Created by meshio v{__version__}, {now}\n".encode()) # counts fh.write(f"element vertex {mesh.points.shape[0]:d}\n".encode()) # dim_names = ["x", "y", "z"] # From : # # > The type can be specified with one of char uchar short ushort int uint float # > double, or one of int8 uint8 int16 uint16 int32 uint32 float32 float64. # # We're adding [u]int64 here. type_name_table = { np.dtype(np.int8): "int8", np.dtype(np.int16): "int16", np.dtype(np.int32): "int32", np.dtype(np.int64): "int64", np.dtype(np.uint8): "uint8", np.dtype(np.uint16): "uint16", np.dtype(np.uint32): "uint32", np.dtype(np.uint64): "uint64", np.dtype(np.float32): "float", np.dtype(np.float64): "double", } for k in range(mesh.points.shape[1]): type_name = type_name_table[mesh.points.dtype] fh.write(f"property {type_name} {dim_names[k]}\n".encode()) pd = [] for key, value in mesh.point_data.items(): if len(value.shape) > 1: warn( "PLY writer doesn't support multidimensional point data yet. " f"Skipping {key}." ) continue type_name = type_name_table[value.dtype] fh.write(f"property {type_name} {key}\n".encode()) pd.append(value) num_cells = 0 legal_cell_types = ["vertex", "line", "triangle", "quad", "polygon"] for cell_block in mesh.cells: if cell_block.type in legal_cell_types: num_cells += cell_block.data.shape[0] if num_cells > 0: fh.write(f"element face {num_cells:d}\n".encode()) # possibly cast down to int32 # TODO don't alter the mesh data has_cast = False for k, cell_block in enumerate(mesh.cells): if cell_block.data.dtype == np.int64: has_cast = True mesh.cells[k] = CellBlock( cell_block.type, cell_block.data.astype(np.int32) ) if has_cast: warn("PLY doesn't support 64-bit integers. Casting down to 32-bit.") # assert that all cell dtypes are equal cell_dtype = None for cell_block in mesh.cells: if cell_dtype is None: cell_dtype = cell_block.data.dtype if cell_block.data.dtype != cell_dtype: raise WriteError() if cell_dtype is not None: ply_type = numpy_to_ply_dtype[cell_dtype] fh.write(f"property list uint8 {ply_type} vertex_indices\n".encode()) # TODO other cell data fh.write(b"end_header\n") if binary: # points and point_data out = np.rec.fromarrays([coord for coord in mesh.points.T] + pd) fh.write(out.tobytes()) # cells for cell_block in mesh.cells: if cell_block.type not in legal_cell_types: warn( f'cell_type "{cell_block.type}" is not supported by PLY format ' "- skipping" ) continue # prepend with count d = cell_block.data out = np.rec.fromarrays( [np.broadcast_to(np.uint8(d.shape[1]), d.shape[0]), *d.T] ) fh.write(out.tobytes()) else: # vertices # np.savetxt(fh, mesh.points, "%r") # slower # out = np.column_stack([mesh.points] + list(mesh.point_data.values())) out = np.rec.fromarrays([coord for coord in mesh.points.T] + pd) fmt = " ".join(["{}"] * len(out[0])) out = "\n".join([fmt.format(*row) for row in out]) + "\n" fh.write(out.encode()) # cells for cell_block in mesh.cells: if cell_block.type not in legal_cell_types: warn( f'cell_type "{cell_block.type}" is not supported by PLY format ' + "- skipping" ) continue # if cell_type not in cell_type_to_count.keys(): # continue d = cell_block.data out = np.column_stack( [np.full(d.shape[0], d.shape[1], dtype=d.dtype), d] ) # savetxt is slower # np.savetxt(fh, out, "%d %d %d %d") fmt = " ".join(["{}"] * out.shape[1]) out = "\n".join([fmt.format(*row) for row in out]) + "\n" fh.write(out.encode()) register_format("ply", [".ply"], read, {"ply": write}) src/meshio/stl/000077500000000000000000000000001456244072500137445ustar00rootroot00000000000000src/meshio/stl/__init__.py000066400000000000000000000000731456244072500160550ustar00rootroot00000000000000from ._stl import read, write __all__ = ["read", "write"] src/meshio/stl/_stl.py000066400000000000000000000177201456244072500152660ustar00rootroot00000000000000""" I/O for the STL format, cf. . """ from __future__ import annotations import os import numpy as np from ..__about__ import __version__ from .._common import warn from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh def read(filename): with open_file(filename, "rb") as f: # Checking if the file is ASCII format is normally done by checking if the # first 5 characters of the header is "solid". # ``` # header = f.read(80).decode() # ``` # Unfortunately, there are mesh files out there which are binary and still put # "solid" there. # A suggested alternative is to pretend the file is binary, read the # num_triangles and see if it matches the file size # (https://stackoverflow.com/a/7394842/353337). filesize_bytes = os.path.getsize(filename) if filesize_bytes < 80: return _read_ascii(f) f.read(80) num_triangles = np.fromfile(f, count=1, dtype=". def iter_loadtxt( infile, skiprows: int = 0, comments: str | tuple[str, ...] = "#", dtype=float, usecols: tuple[int] | None = None, ): def iter_func(): items = None for _ in range(skiprows): try: next(infile) except StopIteration: raise ReadError("EOF Skipped too many rows") for line in infile: line = line.decode().strip() if line.startswith(comments): continue # remove all text items = line.split()[-3:] usecols_ = range(len(items)) if usecols is None else usecols for idx in usecols_: yield dtype(items[idx]) if items is None: iter_loadtxt.rowlength = 3 return iter_loadtxt.rowlength = len(items) if usecols is None else len(usecols) data = np.fromiter(iter_func(), dtype=dtype) return data.reshape((-1, iter_loadtxt.rowlength)) def _read_ascii(f): # The file has the form # ``` # solid foo # facet normal 0.455194 -0.187301 -0.870469 # outer loop # vertex 266.36 234.594 14.6145 # vertex 268.582 234.968 15.6956 # vertex 267.689 232.646 15.7283 # endloop # endfacet # # [...] more facets [...] # endsolid # ``` # In the interest of speed, don't verify the format and instead just skip the text. # TODO Pandas is MUCH faster than numpy for i/o, see # . # import pandas # data = pandas.read_csv( # f, # skiprows=lambda row: row == 0 or (row - 1) % 7 in [0, 1, 5, 6], # skipfooter=1, # usecols=(1, 2, 3), # ) # np.loadtxt is super slow # data = np.loadtxt( # f, # comments=["solid", "facet", "outer loop", "endloop", "endfacet", "endsolid"], # usecols=(1, 2, 3), # ) data = iter_loadtxt( f, comments=("solid", "outer loop", "endloop", "endfacet", "endsolid"), # usecols=(1, 2, 3), ) if data.shape[0] % 4 != 0: raise ReadError() # split off the facet normals facet_rows = np.zeros(len(data), dtype=bool) facet_rows[0::4] = True facet_normals = data[facet_rows] data = data[~facet_rows] if data.shape[0] == 0: points = [] cells = {} cell_data = {} else: facets = np.split(data, data.shape[0] // 3) points, cells = data_from_facets(facets) cell_data = {"facet_normals": [facet_normals]} return Mesh(points, cells, cell_data=cell_data) def data_from_facets(facets): # Now, all facets contain the point coordinate. Try to identify individual points # and build the data arrays. if len(facets) == 0: points = np.empty((0, 3), dtype=float) cells = [] else: pts = np.concatenate(facets) # TODO equip `unique()` with a tolerance # Use return_index so we can use sort on `idx` such that the order is # preserved; see . _, idx, inv = np.unique(pts, axis=0, return_index=True, return_inverse=True) k = np.argsort(idx) points = pts[idx[k]] inv_k = np.argsort(k) cells = [CellBlock("triangle", inv_k[inv].reshape(-1, 3))] return points, cells def _read_binary(f, num_triangles: int): # for each triangle, one has 3 float32 (facet normal), 9 float32 (facet), and 1 # int16 (attribute count) out = np.fromfile( f, count=num_triangles, dtype=np.dtype( [("normal", " 1: invalid = {block.type for block in mesh.cells if block.type != "triangle"} invalid = ", ".join(invalid) warn(f"STL can only write triangle cells. Discarding {invalid}.") if mesh.points.shape[1] == 2: warn( "STL requires 3D points, but 2D points given. Appending 0 third component." ) points = np.column_stack([mesh.points, np.zeros_like(mesh.points[:, 0])]) else: points = mesh.points pts = points[mesh.get_cells_type("triangle")] if "facet_normals" in mesh.cell_data: normals = mesh.get_cell_data("facet_normals", "triangle") else: normals = np.cross(pts[:, 1] - pts[:, 0], pts[:, 2] - pts[:, 0]) nrm = np.sqrt(np.einsum("ij,ij->i", normals, normals)) normals = (normals.T / nrm).T fun = _write_binary if binary else _write_ascii fun(filename, pts, normals) def _write_ascii(filename, pts, normals): with open_file(filename, "w") as fh: fh.write("solid\n") for local_pts, normal in zip(pts, normals): out = ( "\n".join( [ "facet normal {} {} {}".format(*normal), " outer loop", " vertex {} {} {}".format(*local_pts[0]), " vertex {} {} {}".format(*local_pts[1]), " vertex {} {} {}".format(*local_pts[2]), " endloop", "endfacet", ] ) + "\n" ) fh.write(out) fh.write("endsolid\n") def _write_binary(filename, pts, normals): with open_file(filename, "wb") as fh: # 80 character header data msg = f"This file was generated by meshio v{__version__}." msg += (79 - len(msg)) * "X" msg += "\n" fh.write(msg.encode()) fh.write(np.array(len(pts)).astype(" """ from itertools import chain, islice import numpy as np from .._common import _pick_first_int_data, warn from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh # follows VTK conventions su2_type_to_numnodes = { 3: 2, # line 5: 3, # triangle 9: 4, # quad 10: 4, # tetra 12: 8, # hexahedron 13: 6, # wedge 14: 5, # pyramid } su2_to_meshio_type = { 3: "line", 5: "triangle", 9: "quad", 10: "tetra", 12: "hexahedron", 13: "wedge", 14: "pyramid", } meshio_to_su2_type = { "line": 3, "triangle": 5, "quad": 9, "tetra": 10, "hexahedron": 12, "wedge": 13, "pyramid": 14, } def read(filename): with open_file(filename, "r") as f: mesh = read_buffer(f) return mesh def read_buffer(f): cells = [] cell_data = {"su2:tag": []} itype = "i8" ftype = "f8" dim = 0 next_tag_id = 0 expected_nmarkers = 0 markers_found = 0 while True: line = f.readline() if not line: # EOF break line = line.strip() if len(line) == 0: continue if line[0] == "%": continue try: name, rest_of_line = line.split("=") except ValueError: warn(f"meshio could not parse line\n {line}\n skipping.....") continue if name == "NDIME": dim = int(rest_of_line) if dim != 2 and dim != 3: raise ReadError(f"Invalid dimension value {line}") elif name == "NPOIN": # according to documentation rest_of_line should just be a int, # and the next block should be just the coordinates of the points # However, some file have one or two extra indices not related to the # actual coordinates. # So lets read the next line to find its actual number of columns # first_line = f.readline() first_line = first_line.split() first_line = np.array(first_line, dtype=ftype) extra_columns = first_line.shape[0] - dim num_verts = int(rest_of_line.split()[0]) - 1 points = np.fromfile( f, count=num_verts * (dim + extra_columns), dtype=ftype, sep=" " ).reshape(num_verts, dim + extra_columns) # save off any extra info if extra_columns > 0: first_line = first_line[:-extra_columns] points = points[:, :-extra_columns] # add the first line we read separately points = np.vstack([first_line, points]) elif name == "NELEM" or name == "MARKER_ELEMS": # we cannot? read at once using numpy because we do not know the # total size. Read, instead next num_elems as is and re-use the # translate_cells function from vtk reader num_elems = int(rest_of_line) gen = islice(f, num_elems) # some files has an extra int column while other not # We do not need it so make sure we will skip it first_line_str = next(gen) first_line = first_line_str.split() nnodes = su2_type_to_numnodes[int(first_line[0])] has_extra_column = False if nnodes + 1 == len(first_line): has_extra_column = False elif nnodes + 2 == len(first_line): has_extra_column = True else: raise ReadError(f"Invalid number of columns for {name} field") # reset generator gen = chain([first_line_str], gen) cell_array = " ".join([line.rstrip("\n") for line in gen]) cell_array = np.fromiter(cell_array.split(), dtype=itype) cells_, _ = _translate_cells(cell_array, has_extra_column) for eltype, data in cells_.items(): cells.append(CellBlock(eltype, data)) num_block_elems = len(data) if name == "NELEM": cell_data["su2:tag"].append( np.full(num_block_elems, 0, dtype=np.int32) ) else: tags = np.full(num_block_elems, next_tag_id, dtype=np.int32) cell_data["su2:tag"].append(tags) elif name == "NMARK": expected_nmarkers = int(rest_of_line) elif name == "MARKER_TAG": next_tag = rest_of_line try: next_tag_id = int(next_tag) except ValueError: next_tag_id += 1 warn( "meshio does not support tags of string type.\n" f" Surface tag {rest_of_line} will be replaced by {next_tag_id}" ) markers_found += 1 if markers_found != expected_nmarkers: warn( f"expected {expected_nmarkers} markers according to NMARK value " f"but found only {markers_found}" ) # merge boundary elements in a single cellblock per cell type if dim == 2: types = ["line"] else: types = ["triangle", "quad"] indices_to_merge = {} for t in types: indices_to_merge[t] = [] for index, cell_block in enumerate(cells): if cell_block.type in types: indices_to_merge[cell_block.type].append(index) cdata = cell_data["su2:tag"] for type, indices in indices_to_merge.items(): if len(indices) > 1: cells[indices[0]] = CellBlock( type, np.concatenate([cells[i].data for i in indices]) ) cdata[indices[0]] = np.concatenate([cdata[i] for i in indices]) # delete merged blocks idelete = [] for type, indices in indices_to_merge.items(): idelete += indices[1:] for i in sorted(idelete, reverse=True): del cells[i] del cdata[i] cell_data["su2:tag"] = cdata return Mesh(points, cells, cell_data=cell_data) def _translate_cells(data, has_extra_column=False): # adapted from _vtk.py # Translate input array into the cells dictionary. # `data` is a one-dimensional vector with # (vtk cell type, p0, p1, ... ,pk, vtk cell type, p10, p11, ..., p1k, ... entry_offset = 1 if has_extra_column: entry_offset += 1 # Collect types into bins. # See for better # alternatives. types = [] i = 0 while i < len(data): types.append(data[i]) i += su2_type_to_numnodes[data[i]] + entry_offset types = np.array(types) bins = {u: np.where(types == u)[0] for u in np.unique(types)} # Deduct offsets from the cell types. This is much faster than manually # going through the data array. Slight disadvantage: This doesn't work for # cells with a custom number of points. numnodes = np.empty(len(types), dtype=int) for tpe, idx in bins.items(): numnodes[idx] = su2_type_to_numnodes[tpe] offsets = np.cumsum(numnodes + entry_offset) - (numnodes + entry_offset) cells = {} cell_data = {} for tpe, b in bins.items(): meshio_type = su2_to_meshio_type[tpe] nnodes = su2_type_to_numnodes[tpe] indices = np.add.outer(offsets[b], np.arange(1, nnodes + 1)) cells[meshio_type] = data[indices] return cells, cell_data def write(filename, mesh): with open_file(filename, "wb") as f: dim = mesh.points.shape[1] f.write(f"NDIME= {dim}\n".encode()) # Write points num_points = mesh.points.shape[0] f.write(f"NPOIN= {num_points}\n".encode()) np.savetxt(f, mesh.points) # Through warnings about unsupported types for cell_block in mesh.cells: if cell_block.type not in meshio_to_su2_type: warn( ".su2 does not support tags elements of type {}.\n" "Skipping ...".format(type) ) # Write `internal` cells types = None if dim == 2: # `internal` cells are considered to be triangles and quads types = ["triangle", "quad"] else: types = ["tetra", "hexahedron", "wedge", "pyramid"] cells = [c for c in mesh.cells if c.type in types] total_num_volume_cells = sum(len(c.data) for c in cells) f.write(f"NELEM= {total_num_volume_cells}\n".encode()) for cell_block in cells: cell_type = meshio_to_su2_type[cell_block.type] # create a column with the value cell_type type_column = np.full( cell_block.data.shape[0], cell_type, dtype=cell_block.data.dtype, ) # prepend a column with the value cell_type cell_block_to_write = np.column_stack([type_column, cell_block.data]) np.savetxt(f, cell_block_to_write, fmt="%d") # write boundary information labels_key, other = _pick_first_int_data(mesh.cell_data) if labels_key and other: warn( "su2 file format can only write one cell data array. " "Picking {}, skipping {}.".format(labels_key, ", ".join(other)) ) if dim == 2: types = ["line"] else: types = ["triangle", "quad"] tags_per_cell_block = dict() # We want to separate boundary elements in groups of same tag # First, find unique tags and how many elements per tags we have for index, cell_block in enumerate(mesh.cells): if cell_block.type not in types: continue labels = ( mesh.cell_data[labels_key][index] if labels_key else np.ones(len(cell_block), dtype=cell_block.data.dtype) ) # Get unique tags and number of instances of each tag for this Cell block tags_tmp, counts_tmp = np.unique(labels, return_counts=True) for tag, count in zip(tags_tmp, counts_tmp): if tag not in tags_per_cell_block: tags_per_cell_block[tag] = count else: tags_per_cell_block[tag] += count f.write(f"NMARK= {len(tags_per_cell_block)}\n".encode()) # write the blocks you found in previous step for tag, count in tags_per_cell_block.items(): f.write(f"MARKER_TAG= {tag}\n".encode()) f.write(f"MARKER_ELEMS= {count}\n".encode()) for index, (cell_type, data) in enumerate(mesh.cells): if cell_type not in types: continue labels = ( mesh.cell_data[labels_key][index] if labels_key else np.ones(len(data), dtype=data.dtype) ) # Pick elements with given tag mask = np.where(labels == tag) cells_to_write = data[mask] cell_type = meshio_to_su2_type[cell_type] # create a column with the value cell_type type_column = np.full( cells_to_write.shape[0], cell_type, dtype=cells_to_write.dtype, ) # prepend a column with the value cell_type cell_block_to_write = np.column_stack([type_column, cells_to_write]) np.savetxt(f, cell_block_to_write, fmt="%d") return register_format("su2", [".su2"], read, {"su2": write}) src/meshio/svg/000077500000000000000000000000001456244072500137415ustar00rootroot00000000000000src/meshio/svg/__init__.py000066400000000000000000000000551456244072500160520ustar00rootroot00000000000000from ._svg import write __all__ = ["write"] src/meshio/svg/_svg.py000066400000000000000000000064431456244072500152600ustar00rootroot00000000000000from __future__ import annotations from xml.etree import ElementTree as ET import numpy as np from .._exceptions import WriteError from .._helpers import register_format def write( filename, mesh, float_fmt: str = ".3f", stroke_width: str | None = None, # Use a default image_width (not None). If set to None, images will come out at the # width of the mesh (which is okay). Some viewers (e.g., eog) have problems # displaying SVGs of width around 1 since they interpret it as the width in pixels. image_width: int | float | None = 100, # ParaView's default colors fill: str = "#c8c5bd", stroke: str = "#000080", ): if mesh.points.shape[1] == 3 and not np.allclose( mesh.points[:, 2], 0.0, rtol=0.0, atol=1.0e-14 ): raise WriteError( f"SVG can only handle flat 2D meshes (shape: {mesh.points.shape})" ) pts = mesh.points[:, :2].copy() min_x = np.min(pts[:, 0]) if len(pts) > 0 else 0.0 max_x = np.max(pts[:, 0]) if len(pts) > 0 else 0.0 min_y = np.min(pts[:, 1]) if len(pts) > 0 else 0.0 max_y = np.max(pts[:, 1]) if len(pts) > 0 else 0.0 pts[:, 1] = max_y + min_y - pts[:, 1] width = max_x - min_x height = max_y - min_y if image_width is not None and width != 0: scaling_factor = image_width / width min_x *= scaling_factor min_y *= scaling_factor width *= scaling_factor height *= scaling_factor pts *= scaling_factor if stroke_width is None: stroke_width = str(width / 100) fmt = " ".join(4 * [f"{{:{float_fmt}}}"]) svg = ET.Element( "svg", xmlns="http://www.w3.org/2000/svg", version="1.1", viewBox=fmt.format(min_x, min_y, width, height), ) style = ET.SubElement(svg, "style") opts = [ f"fill: {fill}", f"stroke: {stroke}", f"stroke-width: {stroke_width}", "stroke-linejoin:bevel", ] # Use path, not polygon, because svgo converts polygons to paths and doesn't convert # the style alongside. No problem if it's paths all the way. style.text = "path {" + "; ".join(opts) + "}" for cell_block in mesh.cells: if cell_block.type not in ["line", "triangle", "quad"]: continue if cell_block.type == "line": fmt = ( f"M {{:{float_fmt}}} {{:{float_fmt}}}" + f"L {{:{float_fmt}}} {{:{float_fmt}}}" ) elif cell_block.type == "triangle": fmt = ( f"M {{:{float_fmt}}} {{:{float_fmt}}}" + f"L {{:{float_fmt}}} {{:{float_fmt}}}" + f"L {{:{float_fmt}}} {{:{float_fmt}}}" + "Z" ) elif cell_block.type == "quad": fmt = ( f"M {{:{float_fmt}}} {{:{float_fmt}}}" + f"L {{:{float_fmt}}} {{:{float_fmt}}}" + f"L {{:{float_fmt}}} {{:{float_fmt}}}" + f"L {{:{float_fmt}}} {{:{float_fmt}}}" + "Z" ) for cell in cell_block.data: ET.SubElement( svg, "path", d=fmt.format(*pts[cell].flatten()), ) tree = ET.ElementTree(svg) tree.write(filename) register_format("svg", [".svg"], None, {"svg": write}) src/meshio/tecplot/000077500000000000000000000000001456244072500146145ustar00rootroot00000000000000src/meshio/tecplot/__init__.py000066400000000000000000000000771456244072500167310ustar00rootroot00000000000000from ._tecplot import read, write __all__ = ["read", "write"] src/meshio/tecplot/_tecplot.py000066400000000000000000000354511456244072500170070ustar00rootroot00000000000000""" I/O for Tecplot ASCII data format, cf. , . """ import numpy as np from ..__about__ import __version__ as version from .._common import warn from .._exceptions import ReadError, WriteError from .._files import open_file from .._helpers import register_format from .._mesh import Mesh zone_key_to_type = { "T": str, "I": int, "J": int, "K": int, "N": int, "NODES": int, "E": int, "ELEMENTS": int, "F": str, "ET": str, "DATAPACKING": str, "ZONETYPE": str, "NV": int, "VARLOCATION": str, } # 0=ORDERED # 1=FELINESEG # 2=FETRIANGLE # 3=FEQUADRILATERAL # 4=FETETRAHEDRON # 5=FEBRICK # 6=FEPOLYGON # 7=FEPOLYHEDRON tecplot_to_meshio_type = { "LINESEG": "line", "FELINESEG": "line", "TRIANGLE": "triangle", "FETRIANGLE": "triangle", "QUADRILATERAL": "quad", "FEQUADRILATERAL": "quad", "TETRAHEDRON": "tetra", "FETETRAHEDRON": "tetra", "BRICK": "hexahedron", "FEBRICK": "hexahedron", } meshio_to_tecplot_type = { "line": "FELINESEG", "triangle": "FETRIANGLE", "quad": "FEQUADRILATERAL", "tetra": "FETETRAHEDRON", "pyramid": "FEBRICK", "wedge": "FEBRICK", "hexahedron": "FEBRICK", } meshio_only = set(meshio_to_tecplot_type.keys()) meshio_to_tecplot_order = { "line": [0, 1], "triangle": [0, 1, 2], "quad": [0, 1, 2, 3], "tetra": [0, 1, 2, 3], "pyramid": [0, 1, 2, 3, 4, 4, 4, 4], "wedge": [0, 1, 4, 3, 2, 2, 5, 5], "hexahedron": [0, 1, 2, 3, 4, 5, 6, 7], } meshio_to_tecplot_order_2 = { "triangle": [0, 1, 2, 2], "quad": [0, 1, 2, 3], "tetra": [0, 1, 2, 2, 3, 3, 3, 3], "pyramid": [0, 1, 2, 3, 4, 4, 4, 4], "wedge": [0, 1, 4, 3, 2, 2, 5, 5], "hexahedron": [0, 1, 2, 3, 4, 5, 6, 7], } meshio_type_to_ndim = { "line": 1, "triangle": 2, "quad": 2, "tetra": 3, "pyramid": 3, "wedge": 3, "hexahedron": 3, } def read(filename): with open_file(filename, "r") as f: out = read_buffer(f) return out def readline(f): line = f.readline().strip() while line.startswith("#"): line = f.readline().strip() return line def read_buffer(f): variables = None num_data = None zone_format = None zone_type = None is_cell_centered = None data = None cells = None while True: line = readline(f) if line.upper().startswith("VARIABLES"): # Multilines for VARIABLES appears to work only if # variable name is double quoted lines = [line] i = f.tell() line = readline(f).upper() while True: if line.startswith('"'): lines += [line] i = f.tell() line = readline(f).upper() else: f.seek(i) break line = " ".join(lines) variables = _read_variables(line) elif line.upper().startswith("ZONE"): # ZONE can be defined on several lines e.g. # ``` # ZONE NODES = 62533, ELEMENTS = 57982 # , DATAPACKING = BLOCK, ZONETYPE = FEQUADRILATERAL # , VARLOCATION = ([1-2] = NODAL, [3-7] = CELLCENTERED) # ``` # is valid (and understood by ParaView and VisIt). info_lines = [line] i = f.tell() line = readline(f).upper() while True: # check if the first entry can be converted to a float try: float(line.split()[0]) except ValueError: info_lines += [line] i = f.tell() line = readline(f).upper() else: f.seek(i) break line = " ".join(info_lines) assert variables is not None zone = _read_zone(line) ( num_nodes, num_cells, zone_format, zone_type, is_cell_centered, ) = _parse_fezone(zone, variables) num_data = [num_cells if i else num_nodes for i in is_cell_centered] data, cells = _read_zone_data( f, sum(num_data) if zone_format == "FEBLOCK" else num_nodes, num_cells, zone_format, ) break # Only support one zone, no need to read the rest elif not line: break assert num_data is not None assert zone_format is not None assert zone_type is not None assert variables is not None assert is_cell_centered is not None assert data is not None assert cells is not None data = ( np.split(np.concatenate(data), np.cumsum(num_data[:-1])) if zone_format == "FEBLOCK" else np.transpose(data) ) data = {k: v for k, v in zip(variables, data)} point_data, cell_data = {}, {} for i, variable in zip(is_cell_centered, variables): if i: cell_data[variable] = [data[variable]] else: point_data[variable] = data[variable] x = "X" if "X" in point_data.keys() else "x" y = "Y" if "Y" in point_data.keys() else "y" z = "Z" if "Z" in point_data.keys() else "z" if "z" in point_data.keys() else "" points = np.column_stack((point_data.pop(x), point_data.pop(y))) if z: points = np.column_stack((points, point_data.pop(z))) cells = [(tecplot_to_meshio_type[zone_type], cells - 1)] return Mesh(points, cells, point_data, cell_data) def _read_variables(line): # Gather variables in a list line = line.split("=")[1] line = [x for x in line.replace(",", " ").split()] variables = [] i = 0 while i < len(line): if '"' in line[i] and not (line[i].startswith('"') and line[i].endswith('"')): var = f"{line[i]}_{line[i + 1]}" i += 1 else: var = line[i] variables.append(var.replace('"', "")) i += 1 # Check that at least X and Y are defined if "X" not in variables and "x" not in variables: raise ReadError("Variable 'X' not found") if "Y" not in variables and "y" not in variables: raise ReadError("Variable 'Y' not found") return variables def _read_zone(line): # Gather zone entries in a dict line = line[5:] zone = {} # Look for zone title ivar = line.find('"') # If zone contains a title, process it and save the title if ivar >= 0: i1, i2 = ivar, ivar + line[ivar + 1 :].find('"') + 2 zone_title = line[i1 + 1 : i2 - 1] line = line.replace(line[i1:i2], "PLACEHOLDER") else: zone_title = None # Look for VARLOCATION (problematic since it contains both ',' and '=') ivar = line.find("VARLOCATION") # If zone contains VARLOCATION, process it and remove the key/value pair if ivar >= 0: i1, i2 = line.find("("), line.find(")") zone["VARLOCATION"] = line[i1 : i2 + 1].replace(" ", "") line = line[:ivar] + line[i2 + 1 :] # Split remaining key/value pairs separated by '=' line = [x for x in line.replace(",", " ").split() if x != "="] i = 0 while i < len(line): if "=" in line[i]: if not (line[i].startswith("=") or line[i].endswith("=")): key, value = line[i].split("=") else: key = line[i].replace("=", "") value = line[i + 1] i += 1 else: key = line[i] value = line[i + 1].replace("=", "") i += 1 zone[key] = zone_key_to_type[key](value) i += 1 # Add zone title to zone dict if zone_title: zone["T"] = zone_title return zone def _parse_fezone(zone, variables): # Check that the grid is unstructured if "F" in zone.keys(): if zone["F"] not in {"FEPOINT", "FEBLOCK"}: raise ReadError("Tecplot reader can only read finite-element type grids") if "ET" not in zone.keys(): raise ReadError("Element type 'ET' not found") zone_format = zone.pop("F") zone_type = zone.pop("ET") elif "DATAPACKING" in zone.keys(): if "ZONETYPE" not in zone.keys(): raise ReadError("Zone type 'ZONETYPE' not found") zone_format = "FE" + zone.pop("DATAPACKING") zone_type = zone.pop("ZONETYPE") else: raise ReadError("Data format 'F' or 'DATAPACKING' not found") # Number of nodes if "N" in zone.keys(): num_nodes = zone.pop("N") elif "NODES" in zone.keys(): num_nodes = zone.pop("NODES") else: raise ReadError("Number of nodes not found") # Number of elements if "E" in zone.keys(): num_cells = zone.pop("E") elif "ELEMENTS" in zone.keys(): num_cells = zone.pop("ELEMENTS") else: raise ReadError("Number of elements not found") # Variable locations is_cell_centered = np.zeros(len(variables), dtype=int) if zone_format == "FEBLOCK": if "NV" in zone.keys(): node_value = zone.pop("NV") is_cell_centered[node_value:] = 1 elif "VARLOCATION" in zone.keys(): varlocation = zone.pop("VARLOCATION")[1:-1].split(",") for location in varlocation: varrange, varloc = location.split("=") varloc = varloc.strip() if varloc == "CELLCENTERED": varrange = varrange[1:-1].split("-") if len(varrange) == 1: i = int(varrange[0]) - 1 is_cell_centered[i] = 1 else: imin = int(varrange[0]) - 1 imax = int(varrange[1]) - 1 for i in range(imin, imax + 1): is_cell_centered[i] = 1 return num_nodes, num_cells, zone_format, zone_type, is_cell_centered def _read_zone_data(f, num_data, num_cells, zone_format): data, count = [], 0 while count < num_data: line = readline(f).split() if line: data += [[float(x) for x in line]] count += len(line) if zone_format == "FEBLOCK" else 1 cells, count = [], 0 while count < num_cells: line = readline(f).split() if line: cells += [[[int(x) for x in line]]] count += 1 return data, np.concatenate(cells) def write(filename, mesh): # Check cell types cell_types = [] cell_blocks = [] for ic, c in enumerate(mesh.cells): if c.type in meshio_only: cell_types.append(c.type) cell_blocks.append(ic) else: warn( ( "Tecplot does not support cell type '{}'. " "Skipping cell block {}." ).format(c.type, ic) ) # Define cells and zone type cell_types = np.unique(cell_types) if len(cell_types) == 0: raise WriteError("No cell type supported by Tecplot in mesh") elif len(cell_types) == 1: # Nothing much to do except converting pyramids and wedges to hexahedra zone_type = meshio_to_tecplot_type[cell_types[0]] cells = np.concatenate( [ mesh.cells[ic].data[:, meshio_to_tecplot_order[mesh.cells[ic].type]] for ic in cell_blocks ] ) else: # Check if the mesh contains 2D and 3D cells num_dims = [meshio_type_to_ndim[mesh.cells[ic].type] for ic in cell_blocks] # Skip 2D cells if it does if len(np.unique(num_dims)) == 2: warn("Mesh contains 2D and 3D cells. Skipping 2D cells.") cell_blocks = [ic for ic, ndim in zip(cell_blocks, num_dims) if ndim == 3] # Convert 2D cells to quads / 3D cells to hexahedra zone_type = "FEQUADRILATERAL" if num_dims[0] == 2 else "FEBRICK" cells = np.concatenate( [ mesh.cells[ic].data[:, meshio_to_tecplot_order_2[mesh.cells[ic].type]] for ic in cell_blocks ] ) # Define variables variables = ["X", "Y"] data = [mesh.points[:, 0], mesh.points[:, 1]] varrange = [3, 0] if mesh.points.shape[1] == 3: variables += ["Z"] data += [mesh.points[:, 2]] varrange[0] += 1 for k, v in mesh.point_data.items(): if k not in {"X", "Y", "Z", "x", "y", "z"}: if v.ndim == 1: variables += [k] data += [v] varrange[0] += 1 elif v.ndim == 2: for i, vv in enumerate(v.T): variables += [f"{k}_{i}"] data += [vv] varrange[0] += 1 else: warn(f"Skipping point data '{k}'.") if mesh.cell_data: varrange[1] = varrange[0] - 1 for k, v in mesh.cell_data.items(): if k not in {"X", "Y", "Z", "x", "y", "z"}: v = np.concatenate([v[ic] for ic in cell_blocks]) if v.ndim == 1: variables += [k] data += [v] varrange[1] += 1 elif v.ndim == 2: for i, vv in enumerate(v.T): variables += [f"{k}_{i}"] data += [vv] varrange[1] += 1 else: warn(f"Skipping cell data '{k}'.") with open_file(filename, "w") as f: # Title f.write(f'TITLE = "Written by meshio v{version}"\n') # Variables variables_str = ", ".join(f'"{var}"' for var in variables) f.write(f"VARIABLES = {variables_str}\n") # Zone record num_nodes = len(mesh.points) num_cells = sum(len(mesh.cells[ic].data) for ic in cell_blocks) f.write(f"ZONE NODES = {num_nodes}, ELEMENTS = {num_cells},\n") f.write(f"DATAPACKING = BLOCK, ZONETYPE = {zone_type}") if varrange[0] <= varrange[1]: f.write(",\n") varlocation_str = ( f"{varrange[0]}" if varrange[0] == varrange[1] else f"{varrange[0]}-{varrange[1]}" ) f.write(f"VARLOCATION = ([{varlocation_str}] = CELLCENTERED)\n") else: f.write("\n") # Zone data for arr in data: _write_table(f, arr) # CellBlock for cell in cells: f.write(" ".join(str(c) for c in cell + 1) + "\n") def _write_table(f, data, ncol=20): nrow = len(data) // ncol lines = np.split(data, np.full(nrow, ncol).cumsum()) for line in lines: if len(line): f.write(" ".join(str(l) for l in line) + "\n") register_format("tecplot", [".dat", ".tec"], read, {"tecplot": write}) src/meshio/tetgen/000077500000000000000000000000001456244072500144305ustar00rootroot00000000000000src/meshio/tetgen/__init__.py000066400000000000000000000000761456244072500165440ustar00rootroot00000000000000from ._tetgen import read, write __all__ = ["read", "write"] src/meshio/tetgen/_tetgen.py000066400000000000000000000137261456244072500164400ustar00rootroot00000000000000""" I/O for the TetGen file format, c.f. """ import pathlib import numpy as np from ..__about__ import __version__ from .._common import warn from .._exceptions import ReadError, WriteError from .._helpers import register_format from .._mesh import CellBlock, Mesh def read(filename): filename = pathlib.Path(filename) if filename.suffix == ".node": node_filename = filename ele_filename = filename.parent / (filename.stem + ".ele") elif filename.suffix == ".ele": node_filename = filename.parent / (filename.stem + ".node") ele_filename = filename else: raise ReadError() point_data = {} cell_data = {} # read nodes with open(node_filename) as f: line = f.readline().strip() while len(line) == 0 or line[0] == "#": line = f.readline().strip() num_points, dim, num_attrs, num_bmarkers = ( int(item) for item in line.split(" ") if item != "" ) if dim != 3: raise ReadError("Need 3D points.") points = np.fromfile( f, dtype=float, count=(4 + num_attrs + num_bmarkers) * num_points, sep=" " ).reshape(num_points, 4 + num_attrs + num_bmarkers) node_index_base = int(points[0, 0]) # make sure the nodes are numbered consecutively if not np.all( points[:, 0] == np.arange(node_index_base, node_index_base + points.shape[0]) ): raise ReadError() # read point attributes for k in range(num_attrs): point_data[f"tetgen:attr{k + 1}"] = points[:, 4 + k] # read boundary markers, the first is "ref", the others are "ref2", "ref3", ... for k in range(num_bmarkers): flag = "" if k == 0 else str(k + 1) point_data["tetgen:ref" + flag] = points[:, 4 + num_attrs + k] # remove the leading index column, the attributes, and the boundary markers points = points[:, 1:4] # read elements with open(ele_filename.as_posix()) as f: line = f.readline().strip() while len(line) == 0 or line[0] == "#": line = f.readline().strip() num_tets, num_points_per_tet, num_attrs = ( int(item) for item in line.strip().split(" ") if item != "" ) if num_points_per_tet != 4: raise ReadError() cells = np.fromfile( f, dtype=int, count=(5 + num_attrs) * num_tets, sep=" " ).reshape(num_tets, 5 + num_attrs) # read cell (region) attributes, the first is "ref", the others are "ref2", # "ref3", ... for k in range(num_attrs): flag = "" if k == 0 else str(k + 1) cell_data["tetgen:ref" + flag] = [cells[:, 5 + k]] # remove the leading index column and the attributes cells = cells[:, 1:5] cells -= node_index_base return Mesh( points, [CellBlock("tetra", cells)], point_data=point_data, cell_data=cell_data ) def write(filename, mesh, float_fmt=".16e"): filename = pathlib.Path(filename) if filename.suffix == ".node": node_filename = filename ele_filename = filename.parent / (filename.stem + ".ele") elif filename.suffix == ".ele": node_filename = filename.parent / (filename.stem + ".node") ele_filename = filename else: raise WriteError(f"Must specify .node or .ele file. Got {filename}.") if mesh.points.shape[1] != 3: raise WriteError("Can only write 3D points") # write nodes with open(node_filename, "w") as fh: # identify ":ref" key attr_keys = list(mesh.point_data.keys()) ref_keys = [k for k in attr_keys if ":ref" in k] if len(attr_keys) > 0: if len(ref_keys) > 0: ref_keys = ref_keys[:1] attr_keys.remove(ref_keys[0]) else: ref_keys = attr_keys[:1] attr_keys = attr_keys[1:] nattr, nref = len(attr_keys), len(ref_keys) fh.write(f"# This file was created by meshio v{__version__}\n") if (nattr + nref) > 0: fh.write( "# attribute and marker names: {}\n".format( ", ".join(attr_keys + ref_keys) ) ) fh.write(f"{mesh.points.shape[0]} {3} {nattr} {nref}\n") fmt = ( "{} " + " ".join((3 + nattr) * ["{:" + float_fmt + "}"]) + "".join((nref) * [" {}"]) + "\n" ) for k, pt in enumerate(mesh.points): data = ( list(pt[:3]) + [mesh.point_data[key][k] for key in attr_keys] + [mesh.point_data[key][k] for key in ref_keys] ) fh.write(fmt.format(k, *data)) if any(c.type != "tetra" for c in mesh.cells): string = ", ".join([c.type for c in mesh.cells if c.type != "tetra"]) warn(f"TetGen only supports tetrahedra, but mesh has {string}. Skipping those.") # write cells with open(ele_filename, "w") as fh: attr_keys = list(mesh.cell_data.keys()) ref_keys = [k for k in attr_keys if ":ref" in k] if len(attr_keys) > 0: if len(ref_keys) > 0: attr_keys.remove(ref_keys[0]) attr_keys = ref_keys[:1] + attr_keys nattr = len(attr_keys) fh.write(f"# This file was created by meshio v{__version__}\n") if nattr > 0: fh.write("# attribute names: {}\n".format(", ".join(attr_keys))) for id, c in enumerate(filter(lambda c: c.type == "tetra", mesh.cells)): data = c.data fh.write(f"{data.shape[0]} {4} {nattr}\n") fmt = " ".join((5 + nattr) * ["{}"]) + "\n" for k, tet in enumerate(data): data = list(tet[:4]) + [mesh.cell_data[key][id][k] for key in attr_keys] fh.write(fmt.format(k, *data)) register_format("tetgen", [".ele", ".node"], read, {"tetgen": write}) src/meshio/ugrid/000077500000000000000000000000001456244072500142545ustar00rootroot00000000000000src/meshio/ugrid/__init__.py000066400000000000000000000000751456244072500163670ustar00rootroot00000000000000from ._ugrid import read, write __all__ = ["read", "write"] src/meshio/ugrid/_ugrid.py000066400000000000000000000215611456244072500161040ustar00rootroot00000000000000""" I/O for AFLR's UGRID format [1] Check out [2] for UG_IO C code able to read and convert UGRID files Node ordering described in [3] """ import numpy as np from .._common import _pick_first_int_data, warn from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh # Float size and endianness are recorded by these suffixes # binary files come in C-type or FORTRAN type # https://www.simcenter.msstate.edu/software/documentation/ug_io/ugc_file_formats.html # # 64-bit versions described here # https://www.simcenter.msstate.edu/software/documentation/ug_io/ugc_l_file_formats.html file_types = { "ascii": {"type": "ascii", "float_type": "f", "int_type": "i"}, "b8l": {"type": "C", "float_type": ">f8", "int_type": ">i8"}, "b8": {"type": "C", "float_type": ">f8", "int_type": ">i4"}, "b4": {"type": "C", "float_type": ">f4", "int_type": ">i4"}, "lb8l": {"type": "C", "float_type": "f8", "int_type": ">i4"}, "r4": {"type": "F", "float_type": ">f4", "int_type": ">i4"}, "lr8": {"type": "F", "float_type": " 1: type_suffix = filename_parts[-2] if type_suffix in file_types.keys(): file_type = file_types[type_suffix] return file_type def read(filename): file_type = determine_file_type(filename) with open_file(filename) as f: mesh = read_buffer(f, file_type) return mesh def _read_section(f, file_type, count, dtype): if file_type["type"] == "ascii": return np.fromfile(f, count=count, dtype=dtype, sep=" ") return np.fromfile(f, count=count, dtype=dtype) def read_buffer(f, file_type): cells = [] cell_data = [] itype = file_type["int_type"] ftype = file_type["float_type"] # Fortran type includes a number of bytes before and after each record, according to # documentation [1] there are two records in the file; see also UG_IO freely # available code at [2]. if file_type["type"] == "F": _read_section(f, file_type, count=1, dtype=itype) nitems = _read_section(f, file_type, count=7, dtype=itype) if file_type["type"] == "F": _read_section(f, file_type, count=1, dtype=itype) if not nitems.size == 7: raise ReadError("Header of ugrid file is ill-formed") ugrid_counts = { "points": (nitems[0], 3), "triangle": (nitems[1], 3), "quad": (nitems[2], 4), "tetra": (nitems[3], 4), "pyramid": (nitems[4], 5), "wedge": (nitems[5], 6), "hexahedron": (nitems[6], 8), } if file_type["type"] == "F": _read_section(f, file_type, count=1, dtype=itype) nnodes = ugrid_counts["points"][0] points = _read_section(f, file_type, count=nnodes * 3, dtype=ftype).reshape( nnodes, 3 ) for key in ["triangle", "quad"]: nitems = ugrid_counts[key][0] nvertices = ugrid_counts[key][1] if nitems == 0: continue out = _read_section( f, file_type, count=nitems * nvertices, dtype=itype ).reshape(nitems, nvertices) # UGRID is one-based cells.append(CellBlock(key, out - 1)) cell_data = {"ugrid:ref": []} for key in ["triangle", "quad"]: nitems = ugrid_counts[key][0] if nitems == 0: continue out = _read_section(f, file_type, count=nitems, dtype=itype) cell_data["ugrid:ref"].append(out) for key in ["tetra", "pyramid", "wedge", "hexahedron"]: nitems = ugrid_counts[key][0] nvertices = ugrid_counts[key][1] if nitems == 0: continue out = _read_section( f, file_type, count=nitems * nvertices, dtype=itype ).reshape(nitems, nvertices) if key == "pyramid": out = out[:, [1, 0, 3, 4, 2]] # UGRID is one-based cells.append(CellBlock(key, out - 1)) # fill volume element attributes with zero cell_data["ugrid:ref"].append(np.zeros(nitems, dtype=int)) if file_type["type"] == "F": _read_section(f, file_type, count=1, dtype=itype) return Mesh(points, cells, cell_data=cell_data) def _write_section(f, file_type, array, dtype): if file_type["type"] == "ascii": ncols = array.shape[1] fmt = " ".join(["%r"] * ncols) np.savetxt(f, array, fmt=fmt) else: array.astype(dtype).tofile(f) def write(filename, mesh): file_type = determine_file_type(filename) with open_file(filename, "w") as f: _write_buffer(f, file_type, mesh) def _write_buffer(f, file_type, mesh): itype = file_type["int_type"] ftype = file_type["float_type"] ugrid_counts = { "points": 0, "triangle": 0, "quad": 0, "tetra": 0, "pyramid": 0, "wedge": 0, "hexahedron": 0, } # ugrid type to cell array id ugrid_meshio_id = { "points": -1, "triangle": -1, "quad": -1, "tetra": -1, "pyramid": -1, "wedge": -1, "hexahedron": -1, } ugrid_counts["points"] = mesh.points.shape[0] for i, cell_block in enumerate(mesh.cells): key = cell_block.type data = cell_block.data if key in ugrid_counts: if ugrid_counts[key] > 0: raise ValueError("Ugrid can only handle one cell block of a type.") ugrid_counts[key] = data.shape[0] ugrid_meshio_id[key] = i else: msg = f"UGRID mesh format doesn't know {key} cells. Skipping." warn(msg) continue nitems = np.array([list(ugrid_counts.values())]) # header # fortran_header corresponds to the number of bytes in each record # it has to be before and after each record fortran_header = None if file_type["type"] == "F": fortran_header = np.array([nitems.nbytes]) _write_section(f, file_type, fortran_header, itype) _write_section(f, file_type, nitems, itype) if file_type["type"] == "F": # finish current record _write_section(f, file_type, fortran_header, itype) # start next record fortran_header = mesh.points.nbytes for cell_block in mesh.cells: fortran_header += cell_block.data.nbytes # boundary tags if ugrid_counts["triangle"] > 0: fortran_header += ugrid_counts["triangle"] * np.dtype(itype).itemsize if ugrid_counts["quad"] > 0: fortran_header += ugrid_counts["quad"] * np.dtype(itype).itemsize fortran_header = np.array([fortran_header]) _write_section(f, file_type, fortran_header, itype) _write_section(f, file_type, mesh.points, ftype) for key in ["triangle", "quad"]: if ugrid_counts[key] == 0: continue c = mesh.cells[ugrid_meshio_id[key]] # UGRID is one-based _write_section(f, file_type, c.data + 1, itype) # write boundary tags for key in ["triangle", "quad"]: if ugrid_counts[key] == 0: continue # pick out cell data # for data in mesh.cell_data.values(): # if data.dtype in [np.int8, np.int16, np.int32, np.int64]: # labels = data # break # pick out cell_data labels_key, other = _pick_first_int_data(mesh.cell_data) if labels_key and other: warn( "UGRID can only write one cell data array. " f'Picking {labels_key}, skipping {", ".join(other)}.' ) labels = ( mesh.cell_data[labels_key] if labels_key else np.ones(ugrid_counts[key], dtype=int) ) labels = labels.reshape(ugrid_counts[key], 1) _write_section(f, file_type, labels, itype) # write volume elements for key in ["tetra", "pyramid", "wedge", "hexahedron"]: if ugrid_counts[key] == 0: continue c = mesh.cells[ugrid_meshio_id[key]] # UGRID is one-based out = c.data + 1 if c.type == "pyramid": out = out[:, [1, 0, 4, 2, 3]] _write_section(f, file_type, out, itype) if file_type["type"] == "F": _write_section(f, file_type, fortran_header, itype) register_format("ugrid", [".ugrid"], read, {"ugrid": write}) src/meshio/vtk/000077500000000000000000000000001456244072500137465ustar00rootroot00000000000000src/meshio/vtk/__init__.py000066400000000000000000000000741456244072500160600ustar00rootroot00000000000000from ._main import read, write __all__ = ["read", "write"] src/meshio/vtk/_main.py000066400000000000000000000020031456244072500153760ustar00rootroot00000000000000import pathlib from .._exceptions import ReadError from .._helpers import register_format from . import _vtk_42, _vtk_51 def read(filename): filename = pathlib.Path(filename) with open(filename.as_posix(), "rb") as f: mesh = read_buffer(f) return mesh def read_buffer(f): # The first line specifies the version line = f.readline().decode().strip() if not line.startswith("# vtk DataFile Version"): raise ReadError("Illegal VTK header") version = line[23:] if version == "5.1": return _vtk_51.read(f) # this also works for older format versions return _vtk_42.read(f) def write(filename, mesh, fmt_version: str = "5.1", **kwargs): if fmt_version == "4.2": return _vtk_42.write(filename, mesh, **kwargs) assert fmt_version == "5.1" _vtk_51.write(filename, mesh, **kwargs) register_format( "vtk", [".vtk"], read, { "vtk42": _vtk_42.write, "vtk51": _vtk_42.write, "vtk": _vtk_51.write, }, ) src/meshio/vtk/_vtk_42.py000066400000000000000000000601501456244072500155720ustar00rootroot00000000000000""" I/O for VTK . """ from functools import reduce import numpy as np from ..__about__ import __version__ from .._common import warn from .._exceptions import ReadError, WriteError from .._files import open_file from .._mesh import Mesh from .._vtk_common import ( Info, meshio_to_vtk_order, meshio_to_vtk_type, vtk_to_meshio_order, vtk_to_meshio_type, ) vtk_type_to_numnodes = np.array( [ 0, # empty 1, # vertex -1, # poly_vertex 2, # line -1, # poly_line 3, # triangle -1, # triangle_strip -1, # polygon -1, # pixel 4, # quad 4, # tetra -1, # voxel 8, # hexahedron 6, # wedge 5, # pyramid 10, # penta_prism 12, # hexa_prism -1, -1, -1, -1, 3, # line3 6, # triangle6 8, # quad8 10, # tetra10 20, # hexahedron20 15, # wedge15 13, # pyramid13 9, # quad9 27, # hexahedron27 6, # quad6 12, # wedge12 18, # wedge18 24, # hexahedron24 7, # triangle7 4, # line4 ] ) # These are all VTK data types. vtk_to_numpy_dtype_name = { "bit": "bool", "unsigned_char": "uint8", "char": "int8", "unsigned_short": "uint16", "short": "int16", "unsigned_int": "uint32", "int": "int32", "unsigned_long": "uint64", "long": "int64", "float": "float32", "double": "float64", } numpy_to_vtk_dtype = {v: k for k, v in vtk_to_numpy_dtype_name.items()} # supported vtk dataset types vtk_dataset_types = [ "UNSTRUCTURED_GRID", "STRUCTURED_POINTS", "STRUCTURED_GRID", "RECTILINEAR_GRID", ] # additional infos per dataset type vtk_dataset_infos = { "UNSTRUCTURED_GRID": [], "STRUCTURED_POINTS": [ "DIMENSIONS", "ORIGIN", "SPACING", "ASPECT_RATIO", # alternative for SPACING in version 1.0 and 2.0 ], "STRUCTURED_GRID": ["DIMENSIONS"], "RECTILINEAR_GRID": [ "DIMENSIONS", "X_COORDINATES", "Y_COORDINATES", "Z_COORDINATES", ], } # all main sections in vtk vtk_sections = [ "METADATA", "DATASET", "POINTS", "CELLS", "CELL_TYPES", "POINT_DATA", "CELL_DATA", "LOOKUP_TABLE", "COLOR_SCALARS", ] def read(filename): with open_file(filename, "rb") as f: out = read_buffer(f) return out def read_buffer(f): # initialize output data info = Info() # skip title comment f.readline() data_type = f.readline().decode().strip().upper() if data_type not in ["ASCII", "BINARY"]: raise ReadError(f"Unknown VTK data type '{data_type}'.") info.is_ascii = data_type == "ASCII" while True: line = f.readline().decode() if not line: # EOF break line = line.strip() if len(line) == 0: continue info.split = line.split() info.section = info.split[0].upper() if info.section in vtk_sections: _read_section(f, info) else: _read_subsection(f, info) _check_mesh(info) cells, cell_data = translate_cells( info.connectivity, info.types, info.cell_data_raw ) return Mesh( info.points, cells, point_data=info.point_data, cell_data=cell_data, field_data=info.field_data, ) def _read_section(f, info): if info.section == "METADATA": _skip_meta(f) elif info.section == "DATASET": info.active = "DATASET" info.dataset["type"] = info.split[1].upper() if info.dataset["type"] not in vtk_dataset_types: raise ReadError( "Only VTK '{}' supported (not {}).".format( "', '".join(vtk_dataset_types), info.dataset["type"] ) ) elif info.section == "POINTS": info.active = "POINTS" info.num_points = int(info.split[1]) data_type = info.split[2].lower() info.points = _read_points(f, data_type, info.is_ascii, info.num_points) elif info.section == "CELLS": info.active = "CELLS" info.num_items = int(info.split[2]) info.connectivity = _read_int_data(f, info.is_ascii, info.num_items) elif info.section == "CELL_TYPES": info.active = "CELL_TYPES" info.num_items = int(info.split[1]) info.types = _read_cell_types(f, info.is_ascii, info.num_items) elif info.section == "POINT_DATA": info.active = "POINT_DATA" info.num_items = int(info.split[1]) elif info.section == "CELL_DATA": info.active = "CELL_DATA" info.num_items = int(info.split[1]) elif info.section == "LOOKUP_TABLE": info.num_items = int(info.split[2]) np.fromfile(f, count=info.num_items * 4, sep=" ", dtype=float) # rgba = data.reshape((info.num_items, 4)) elif info.section == "COLOR_SCALARS": nValues = int(info.split[2]) # re-use num_items from active POINT/CELL_DATA num_items = info.num_items dtype = np.ubyte if info.is_ascii: dtype = float np.fromfile(f, count=num_items * nValues, dtype=dtype) def _read_subsection(f, info): if info.active == "POINT_DATA": d = info.point_data elif info.active == "CELL_DATA": d = info.cell_data_raw elif info.active == "DATASET": d = info.dataset else: d = info.field_data if info.section in vtk_dataset_infos[info.dataset["type"]]: if info.section[1:] == "_COORDINATES": info.num_points = int(info.split[1]) data_type = info.split[2].lower() d[info.section] = _read_coords(f, data_type, info.is_ascii, info.num_points) else: if info.section == "DIMENSIONS": d[info.section] = list(map(int, info.split[1:])) else: d[info.section] = list(map(float, info.split[1:])) if len(d[info.section]) != 3: raise ReadError( "Wrong number of info in section '{}'. Need 3, got {}.".format( info.section, len(d[info.section]) ) ) elif info.section == "SCALARS": d.update(_read_scalar_field(f, info.num_items, info.split, info.is_ascii)) elif info.section == "VECTORS": d.update(_read_field(f, info.num_items, info.split, [3], info.is_ascii)) elif info.section == "TENSORS": d.update(_read_field(f, info.num_items, info.split, [3, 3], info.is_ascii)) elif info.section == "FIELD": d.update(_read_fields(f, int(info.split[2]), info.is_ascii)) else: raise ReadError(f"Unknown section '{info.section}'.") def _check_mesh(info): if info.dataset["type"] == "UNSTRUCTURED_GRID": if info.connectivity is None: raise ReadError("Required section CELLS not found.") if info.types is None: raise ReadError("Required section CELL_TYPES not found.") elif info.dataset["type"] == "STRUCTURED_POINTS": dim = info.dataset["DIMENSIONS"] ori = info.dataset["ORIGIN"] spa = ( info.dataset["SPACING"] if "SPACING" in info.dataset else info.dataset["ASPECT_RATIO"] ) axis = [ np.linspace(ori[i], ori[i] + (dim[i] - 1.0) * spa[i], dim[i]) for i in range(3) ] info.points = _generate_points(axis) info.connectivity, info.types = _generate_cells(dim=info.dataset["DIMENSIONS"]) elif info.dataset["type"] == "RECTILINEAR_GRID": axis = [ info.dataset["X_COORDINATES"], info.dataset["Y_COORDINATES"], info.dataset["Z_COORDINATES"], ] info.points = _generate_points(axis) info.connectivity, info.types = _generate_cells(dim=info.dataset["DIMENSIONS"]) elif info.dataset["type"] == "STRUCTURED_GRID": info.connectivity, info.types = _generate_cells(dim=info.dataset["DIMENSIONS"]) def _generate_cells(dim): ele_dim = [d - 1 for d in dim if d > 1] # TODO use math.prod when requiring Python 3.8+? this would save the int conversion # ele_no = int(np.prod(ele_dim)) spatial_dim = len(ele_dim) if spatial_dim == 1: # cells are lines in 1D cells = np.empty((ele_no, 3), dtype=int) cells[:, 0] = 2 cells[:, 1] = np.arange(ele_no, dtype=int) cells[:, 2] = cells[:, 1] + 1 cell_types = np.full(ele_no, 3, dtype=int) elif spatial_dim == 2: # cells are quad in 2D cells = np.empty((ele_no, 5), dtype=int) cells[:, 0] = 4 cells[:, 1] = np.arange(0, ele_no, dtype=int) cells[:, 1] += np.arange(0, ele_no, dtype=int) // ele_dim[0] cells[:, 2] = cells[:, 1] + 1 cells[:, 3] = cells[:, 1] + 2 + ele_dim[0] cells[:, 4] = cells[:, 3] - 1 cell_types = np.full(ele_no, 9, dtype=int) else: # cells are hex in 3D cells = np.empty((ele_no, 9), dtype=int) cells[:, 0] = 8 cells[:, 1] = np.arange(ele_no) cells[:, 1] += (ele_dim[0] + ele_dim[1] + 1) * ( np.arange(ele_no) // (ele_dim[0] * ele_dim[1]) ) cells[:, 1] += (np.arange(ele_no) % (ele_dim[0] * ele_dim[1])) // ele_dim[0] cells[:, 2] = cells[:, 1] + 1 cells[:, 3] = cells[:, 1] + 2 + ele_dim[0] cells[:, 4] = cells[:, 3] - 1 cells[:, 5] = cells[:, 1] + (1 + ele_dim[0]) * (1 + ele_dim[1]) cells[:, 6] = cells[:, 5] + 1 cells[:, 7] = cells[:, 5] + 2 + ele_dim[0] cells[:, 8] = cells[:, 7] - 1 cell_types = np.full(ele_no, 12, dtype=int) return cells.reshape(-1), cell_types def _generate_points(axis): x_dim = len(axis[0]) y_dim = len(axis[1]) z_dim = len(axis[2]) pnt_no = x_dim * y_dim * z_dim x_id, y_id, z_id = np.mgrid[0:x_dim, 0:y_dim, 0:z_dim] points = np.empty((pnt_no, 3), dtype=axis[0].dtype) # VTK sorts points and cells in Fortran order points[:, 0] = axis[0][x_id.reshape(-1, order="F")] points[:, 1] = axis[1][y_id.reshape(-1, order="F")] points[:, 2] = axis[2][z_id.reshape(-1, order="F")] return points def _read_coords(f, data_type, is_ascii, num_points): dtype = np.dtype(vtk_to_numpy_dtype_name[data_type]) if is_ascii: coords = np.fromfile(f, count=num_points, sep=" ", dtype=dtype) else: # Binary data is big endian, see # . dtype = dtype.newbyteorder(">") coords = np.fromfile(f, count=num_points, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() return coords def _read_points(f, data_type, is_ascii, num_points): dtype = np.dtype(vtk_to_numpy_dtype_name[data_type]) if is_ascii: points = np.fromfile(f, count=num_points * 3, sep=" ", dtype=dtype) else: # Binary data is big endian, see # . dtype = dtype.newbyteorder(">") points = np.fromfile(f, count=num_points * 3, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() return points.reshape((num_points, 3)) def _read_int_data(f, is_ascii, num_items, dtype=np.dtype("int32")): if is_ascii: c = np.fromfile(f, count=num_items, sep=" ", dtype=dtype) else: dtype = dtype.newbyteorder(">") c = np.fromfile(f, count=num_items, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() return c def _read_cell_types(f, is_ascii, num_items): if is_ascii: ct = np.fromfile(f, count=int(num_items), sep=" ", dtype=int) else: # binary ct = np.fromfile(f, count=int(num_items), dtype=">i4") line = f.readline().decode() # Sometimes, there's no newline at the end if line.strip() != "": raise ReadError() return ct def _read_scalar_field(f, num_data, split, is_ascii): data_name = split[1] data_type = split[2].lower() try: num_comp = int(split[3]) except IndexError: num_comp = 1 # The standard says: # > The parameter numComp must range between (1,4) inclusive; [...] if not (0 < num_comp < 5): raise ReadError("The parameter numComp must range between (1,4) inclusive") dtype = np.dtype(vtk_to_numpy_dtype_name[data_type]) lt, _ = f.readline().decode().split() if lt.upper() != "LOOKUP_TABLE": raise ReadError() if is_ascii: data = np.fromfile(f, count=num_data * num_comp, sep=" ", dtype=dtype) else: # Binary data is big endian, see # . dtype = dtype.newbyteorder(">") data = np.fromfile(f, count=num_data * num_comp, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() data = data.reshape(-1, num_comp) return {data_name: data} def _read_field(f, num_data, split, shape, is_ascii): data_name = split[1] data_type = split[2].lower() dtype = np.dtype(vtk_to_numpy_dtype_name[data_type]) # prod() # k = reduce((lambda x, y: x * y), shape) if is_ascii: data = np.fromfile(f, count=k * num_data, sep=" ", dtype=dtype) else: # Binary data is big endian, see # . dtype = dtype.newbyteorder(">") data = np.fromfile(f, count=k * num_data, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() data = data.reshape(-1, *shape) return {data_name: data} def _read_fields(f, num_fields, is_ascii): data = {} for _ in range(num_fields): line = f.readline().decode().split() if line[0] == "METADATA": _skip_meta(f) name, shape0, shape1, data_type = f.readline().decode().split() else: name, shape0, shape1, data_type = line shape0 = int(shape0) shape1 = int(shape1) dtype = np.dtype(vtk_to_numpy_dtype_name[data_type.lower()]) if is_ascii: dat = np.fromfile(f, count=shape0 * shape1, sep=" ", dtype=dtype) else: # Binary data is big endian, see # . dtype = dtype.newbyteorder(">") dat = np.fromfile(f, count=shape0 * shape1, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() if shape0 != 1: dat = dat.reshape((shape1, shape0)) data[name] = dat return data def _skip_meta(f): # skip possible metadata # https://vtk.org/doc/nightly/html/IOLegacyInformationFormat.html while True: line = f.readline().decode().strip() if not line: # end of metadata is a blank line break def translate_cells(connectivity, types, cell_data_raw): # https://vtk.org/doc/nightly/html/vtkCellType_8h_source.html # Translate it into the cells array. # `data` is a one-dimensional vector with # (num_points0, p0, p1, ... ,pk, numpoints1, p10, p11, ..., p1k, ... # or a tuple with (offsets, connectivity) has_polygon = np.any(types == meshio_to_vtk_type["polygon"]) cells = [] cell_data = {} if has_polygon: numnodes = np.empty(len(types), dtype=int) # If some polygons are in the VTK file, loop over the cells numcells = len(types) offsets = np.empty(len(types), dtype=int) offsets[0] = 0 for idx in range(numcells - 1): numnodes[idx] = connectivity[offsets[idx]] offsets[idx + 1] = offsets[idx] + numnodes[idx] + 1 idx = numcells - 1 numnodes[idx] = connectivity[offsets[idx]] if not np.all(numnodes == connectivity[offsets]): raise ReadError() # TODO: cell_data for idx, vtk_cell_type in enumerate(types): start = offsets[idx] + 1 new_order = vtk_to_meshio_order(vtk_cell_type, offsets.dtype) if new_order is None: new_order = np.arange(numnodes[idx], dtype=offsets.dtype) cell_idx = start + new_order cell = connectivity[cell_idx] cell_type = vtk_to_meshio_type[vtk_cell_type] if ( len(cells) > 0 and cells[-1][0] == cell_type # the following check if needed for polygons; key can be equal, but # still needs to go into a new block and len(cell) == len(cells[-1][1][-1]) ): cells[-1][1].append(cell) else: # open up a new cell block cells.append((cell_type, [cell])) else: # Infer offsets from the cell types. This is much faster than manually going # through the data array. Slight disadvantage: This doesn't work for cells with # a custom number of points. if np.any(types >= len(vtk_type_to_numnodes)): illegal_types = ", ".join( str(item) for item in set(types[types >= len(vtk_type_to_numnodes)]) ) raise ReadError( f"File contains cells that meshio cannot handle (types {illegal_types})" ) numnodes = vtk_type_to_numnodes[types] if not np.all(numnodes > 0): raise ReadError("File contains cells that meshio cannot handle.") offsets = np.cumsum(numnodes + 1) - (numnodes + 1) if not np.all(numnodes == connectivity[offsets]): raise ReadError() idx0 = 1 b = np.concatenate( [[0], np.where(types[:-1] != types[1:])[0] + 1, [len(types)]] ) for start, end in zip(b[:-1], b[1:]): if start == end: continue meshio_type = vtk_to_meshio_type[types[start]] n = numnodes[start] new_order = vtk_to_meshio_order(types[start], dtype=offsets.dtype) if new_order is None: cell_idx = idx0 + np.arange(0, n, dtype=offsets.dtype) else: cell_idx = idx0 + new_order indices = np.add.outer(offsets[start:end], cell_idx) cells.append((meshio_type, connectivity[indices])) for name, d in cell_data_raw.items(): if name not in cell_data: cell_data[name] = [] cell_data[name].append(d[start:end]) return cells, cell_data def write(filename, mesh, binary=True): def pad(array): return np.pad(array, ((0, 0), (0, 1)), "constant") if mesh.points.shape[1] == 2: warn( "VTK requires 3D points, but 2D points given. " + "Appending 0 third component." ) points = pad(mesh.points) else: points = mesh.points if mesh.point_data: for name, values in mesh.point_data.items(): if len(values.shape) == 2 and values.shape[1] == 2: warn( "VTK requires 3D vectors, but 2D vectors given. " + f"Appending 0 third component to {name}." ) mesh.point_data[name] = pad(values) for name, data in mesh.cell_data.items(): for k, values in enumerate(data): if len(values.shape) == 2 and values.shape[1] == 2: warn( "VTK requires 3D vectors, but 2D vectors given. " + f"Appending 0 third component to {name}." ) data[k] = pad(data[k]) if not binary: warn("VTK ASCII files are only meant for debugging.") with open_file(filename, "wb") as f: f.write(b"# vtk DataFile Version 4.2\n") f.write(f"written by meshio v{__version__}\n".encode()) f.write(("BINARY\n" if binary else "ASCII\n").encode()) f.write(b"DATASET UNSTRUCTURED_GRID\n") # write points and cells _write_points(f, points, binary) _write_cells(f, mesh.cells, binary) # write point data if mesh.point_data: num_points = mesh.points.shape[0] f.write(f"POINT_DATA {num_points}\n".encode()) _write_field_data(f, mesh.point_data, binary) # write cell data if mesh.cell_data: total_num_cells = sum(len(c.data) for c in mesh.cells) f.write(f"CELL_DATA {total_num_cells}\n".encode()) _write_field_data(f, mesh.cell_data, binary) def _write_points(f, points, binary): f.write( "POINTS {} {}\n".format( len(points), numpy_to_vtk_dtype[points.dtype.name] ).encode() ) if binary: # Binary data must be big endian, see # . # if points.dtype.byteorder == "<" or ( # points.dtype.byteorder == "=" and sys.byteorder == "little" # ): # logging.warn("Converting to new byte order") points.astype(points.dtype.newbyteorder(">")).tofile(f, sep="") else: # ascii points.tofile(f, sep=" ") f.write(b"\n") def _write_cells(f, cells, binary): total_num_cells = sum(len(c.data) for c in cells) total_num_idx = sum(c.data.size for c in cells) # For each cell, the number of nodes is stored total_num_idx += total_num_cells f.write(f"CELLS {total_num_cells} {total_num_idx}\n".encode()) if binary: for c in cells: n = c.data.shape[1] d = c.data new_order = meshio_to_vtk_order(c.type) if new_order is not None: d = d[:, new_order] dtype = np.dtype(">i4") # One must force endianness here: # np.column_stack( [np.full(d.shape[0], n, dtype=dtype), d.astype(dtype)], ).astype(dtype).tofile(f, sep="") f.write(b"\n") else: # ascii for c in cells: n = c.data.shape[1] d = c.data new_order = meshio_to_vtk_order(c.type) if new_order is not None: d = d[:, new_order] # prepend a column with the value n np.column_stack( [np.full(c.data.shape[0], n, dtype=c.data.dtype), d] ).tofile(f, sep="\n") f.write(b"\n") # write cell types f.write(f"CELL_TYPES {total_num_cells}\n".encode()) if binary: for c in cells: vtk_type = meshio_to_vtk_type[c.type] np.full(len(c.data), vtk_type, dtype=np.dtype(">i4")).tofile(f, sep="") f.write(b"\n") else: # ascii for c in cells: vtk_type = meshio_to_vtk_type[c.type] np.full(len(c.data), vtk_type).tofile(f, sep="\n") f.write(b"\n") def _write_field_data(f, data, binary): f.write((f"FIELD FieldData {len(data)}\n").encode()) for name, values in data.items(): if isinstance(values, list): values = np.concatenate(values) if len(values.shape) == 1: num_tuples = values.shape[0] num_components = 1 else: num_tuples = values.shape[0] num_components = values.shape[1] if " " in name: raise WriteError(f"VTK doesn't support spaces in field names ('{name}').") f.write( ( "{} {} {} {}\n".format( name, num_components, num_tuples, numpy_to_vtk_dtype[values.dtype.name], ) ).encode() ) if binary: values.astype(values.dtype.newbyteorder(">")).tofile(f, sep="") else: # ascii values.tofile(f, sep=" ") # np.savetxt(f, points) f.write(b"\n") src/meshio/vtk/_vtk_51.py000066400000000000000000000520731456244072500155770ustar00rootroot00000000000000from functools import reduce import numpy as np from ..__about__ import __version__ from .._common import info, join_strings, replace_space, warn from .._exceptions import ReadError, WriteError from .._files import open_file from .._mesh import Mesh from .._vtk_common import ( Info, meshio_to_vtk_order, meshio_to_vtk_type, vtk_cells_from_data, ) # VTK 5.1 data types vtk_to_numpy_dtype_name = { "float": "float32", "double": "float64", "int": "int", "vtktypeint8": "int8", "vtktypeint16": "int16", "vtktypeint32": "int32", "vtktypeint64": "int64", "vtktypeuint8": "uint8", "vtktypeuint16": "uint16", "vtktypeuint32": "uint32", "vtktypeuint64": "uint64", } numpy_to_vtk_dtype = {v: k for k, v in vtk_to_numpy_dtype_name.items()} # supported vtk dataset types vtk_dataset_types = [ "UNSTRUCTURED_GRID", "STRUCTURED_POINTS", "STRUCTURED_GRID", "RECTILINEAR_GRID", ] # additional infos per dataset type vtk_dataset_infos = { "UNSTRUCTURED_GRID": [], "STRUCTURED_POINTS": [ "DIMENSIONS", "ORIGIN", "SPACING", "ASPECT_RATIO", # alternative for SPACING in version 1.0 and 2.0 ], "STRUCTURED_GRID": ["DIMENSIONS"], "RECTILINEAR_GRID": [ "DIMENSIONS", "X_COORDINATES", "Y_COORDINATES", "Z_COORDINATES", ], } # all main sections in vtk vtk_sections = [ "METADATA", "DATASET", "POINTS", "CELLS", "CELL_TYPES", "POINT_DATA", "CELL_DATA", "LOOKUP_TABLE", "COLOR_SCALARS", ] def read(filename): with open_file(filename, "rb") as f: out = read_buffer(f) return out def read_buffer(f): # initialize output data info = Info() # skip title comment f.readline() data_type = f.readline().decode().strip().upper() if data_type not in ["ASCII", "BINARY"]: raise ReadError(f"Unknown VTK data type '{data_type}'.") info.is_ascii = data_type == "ASCII" while True: line = f.readline().decode() if not line: # EOF break line = line.strip() if len(line) == 0: continue info.split = line.split() info.section = info.split[0].upper() if info.section in vtk_sections: _read_section(f, info) else: _read_subsection(f, info) _check_mesh(info) cells, cell_data = vtk_cells_from_data( info.connectivity, info.offsets, info.types, info.cell_data_raw ) return Mesh( info.points, cells, point_data=info.point_data, cell_data=cell_data, field_data=info.field_data, ) def _read_section(f, info): if info.section == "METADATA": _skip_meta(f) elif info.section == "DATASET": info.active = "DATASET" info.dataset["type"] = info.split[1].upper() if info.dataset["type"] not in vtk_dataset_types: legal = ", ".join(vtk_dataset_types) raise ReadError( f"Only VTK '{legal}' supported (not {info.dataset['type']})." ) elif info.section == "POINTS": info.active = "POINTS" info.num_points = int(info.split[1]) data_type = info.split[2].lower() info.points = _read_points(f, data_type, info.is_ascii, info.num_points) elif info.section == "CELLS": info.active = "CELLS" try: line = f.readline().decode() except UnicodeDecodeError: line = "" assert line.startswith("OFFSETS") # vtk DataFile Version 5.1 - appearing in Paraview 5.8.1 outputs # No specification found for this file format. # See the question on ParaView Discourse Forum: # https://discourse.paraview.org/t/specification-of-vtk-datafile-version-5-1/5127 info.num_offsets = int(info.split[1]) info.num_items = int(info.split[2]) dtype = np.dtype(vtk_to_numpy_dtype_name[line.split()[1]]) offsets = _read_int_data(f, info.is_ascii, info.num_offsets, dtype) line = f.readline().decode() assert line.startswith("CONNECTIVITY") dtype = np.dtype(vtk_to_numpy_dtype_name[line.split()[1]]) connectivity = _read_int_data(f, info.is_ascii, info.num_items, dtype) info.connectivity = connectivity assert offsets[0] == 0 assert offsets[-1] == len(connectivity) info.offsets = offsets[1:] elif info.section == "CELL_TYPES": info.active = "CELL_TYPES" info.num_items = int(info.split[1]) info.types = _read_cell_types(f, info.is_ascii, info.num_items) elif info.section == "POINT_DATA": info.active = "POINT_DATA" info.num_items = int(info.split[1]) elif info.section == "CELL_DATA": info.active = "CELL_DATA" info.num_items = int(info.split[1]) elif info.section == "LOOKUP_TABLE": info.num_items = int(info.split[2]) np.fromfile(f, count=info.num_items * 4, sep=" ", dtype=float) # rgba = data.reshape((info.num_items, 4)) elif info.section == "COLOR_SCALARS": nValues = int(info.split[2]) # re-use num_items from active POINT/CELL_DATA num_items = info.num_items dtype = np.ubyte if info.is_ascii: dtype = float np.fromfile(f, count=num_items * nValues, dtype=dtype) def _read_subsection(f, info): if info.active == "POINT_DATA": d = info.point_data elif info.active == "CELL_DATA": d = info.cell_data_raw elif info.active == "DATASET": d = info.dataset else: d = info.field_data if info.section in vtk_dataset_infos[info.dataset["type"]]: if info.section[1:] == "_COORDINATES": info.num_points = int(info.split[1]) data_type = info.split[2].lower() d[info.section] = _read_coords(f, data_type, info.is_ascii, info.num_points) else: if info.section == "DIMENSIONS": d[info.section] = list(map(int, info.split[1:])) else: d[info.section] = list(map(float, info.split[1:])) if len(d[info.section]) != 3: raise ReadError( f"Wrong number of info in section '{info.section}'. " f"Need 3, got {len(d[info.section])}." ) elif info.section == "SCALARS": d.update(_read_scalar_field(f, info.num_items, info.split, info.is_ascii)) elif info.section == "VECTORS": d.update(_read_field(f, info.num_items, info.split, [3], info.is_ascii)) elif info.section == "TENSORS": d.update(_read_field(f, info.num_items, info.split, [3, 3], info.is_ascii)) elif info.section == "FIELD": d.update(_read_fields(f, int(info.split[2]), info.is_ascii)) else: raise ReadError(f"Unknown section '{info.section}'.") def _check_mesh(info): if info.dataset["type"] == "UNSTRUCTURED_GRID": if info.connectivity is None: raise ReadError("Required section CELLS not found.") if info.types is None: raise ReadError("Required section CELL_TYPES not found.") elif info.dataset["type"] == "STRUCTURED_POINTS": dim = info.dataset["DIMENSIONS"] ori = info.dataset["ORIGIN"] spa = ( info.dataset["SPACING"] if "SPACING" in info.dataset else info.dataset["ASPECT_RATIO"] ) axis = [ np.linspace(ori[i], ori[i] + (dim[i] - 1.0) * spa[i], dim[i]) for i in range(3) ] info.points = _generate_points(axis) info.connectivity, info.types = _generate_cells(dim=info.dataset["DIMENSIONS"]) elif info.dataset["type"] == "RECTILINEAR_GRID": axis = [ info.dataset["X_COORDINATES"], info.dataset["Y_COORDINATES"], info.dataset["Z_COORDINATES"], ] info.points = _generate_points(axis) info.connectivity, info.types = _generate_cells(dim=info.dataset["DIMENSIONS"]) elif info.dataset["type"] == "STRUCTURED_GRID": info.connectivity, info.types = _generate_cells(dim=info.dataset["DIMENSIONS"]) def _generate_cells(dim): ele_dim = [d - 1 for d in dim if d > 1] # TODO use math.prod when requiring Python 3.8+? this would save the int conversion # ele_no = int(np.prod(ele_dim)) spatial_dim = len(ele_dim) if spatial_dim == 1: # cells are lines in 1D cells = np.empty((ele_no, 3), dtype=int) cells[:, 0] = 2 cells[:, 1] = np.arange(ele_no, dtype=int) cells[:, 2] = cells[:, 1] + 1 cell_types = np.full(ele_no, 3, dtype=int) elif spatial_dim == 2: # cells are quad in 2D cells = np.empty((ele_no, 5), dtype=int) cells[:, 0] = 4 cells[:, 1] = np.arange(0, ele_no, dtype=int) cells[:, 1] += np.arange(0, ele_no, dtype=int) // ele_dim[0] cells[:, 2] = cells[:, 1] + 1 cells[:, 3] = cells[:, 1] + 2 + ele_dim[0] cells[:, 4] = cells[:, 3] - 1 cell_types = np.full(ele_no, 9, dtype=int) else: # cells are hex in 3D cells = np.empty((ele_no, 9), dtype=int) cells[:, 0] = 8 cells[:, 1] = np.arange(ele_no) cells[:, 1] += (ele_dim[0] + ele_dim[1] + 1) * ( np.arange(ele_no) // (ele_dim[0] * ele_dim[1]) ) cells[:, 1] += (np.arange(ele_no) % (ele_dim[0] * ele_dim[1])) // ele_dim[0] cells[:, 2] = cells[:, 1] + 1 cells[:, 3] = cells[:, 1] + 2 + ele_dim[0] cells[:, 4] = cells[:, 3] - 1 cells[:, 5] = cells[:, 1] + (1 + ele_dim[0]) * (1 + ele_dim[1]) cells[:, 6] = cells[:, 5] + 1 cells[:, 7] = cells[:, 5] + 2 + ele_dim[0] cells[:, 8] = cells[:, 7] - 1 cell_types = np.full(ele_no, 12, dtype=int) return cells.reshape(-1), cell_types def _generate_points(axis): x_dim = len(axis[0]) y_dim = len(axis[1]) z_dim = len(axis[2]) pnt_no = x_dim * y_dim * z_dim x_id, y_id, z_id = np.mgrid[0:x_dim, 0:y_dim, 0:z_dim] points = np.empty((pnt_no, 3), dtype=axis[0].dtype) # VTK sorts points and cells in Fortran order points[:, 0] = axis[0][x_id.reshape(-1, order="F")] points[:, 1] = axis[1][y_id.reshape(-1, order="F")] points[:, 2] = axis[2][z_id.reshape(-1, order="F")] return points def _read_coords(f, data_type, is_ascii, num_points): dtype = np.dtype(vtk_to_numpy_dtype_name[data_type]) if is_ascii: coords = np.fromfile(f, count=num_points, sep=" ", dtype=dtype) else: # Binary data is big endian, see # . dtype = dtype.newbyteorder(">") coords = np.fromfile(f, count=num_points, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() return coords def _read_points(f, data_type, is_ascii, num_points): dtype = np.dtype(vtk_to_numpy_dtype_name[data_type]) if is_ascii: points = np.fromfile(f, count=num_points * 3, sep=" ", dtype=dtype) else: # Binary data is big endian, see # . dtype = dtype.newbyteorder(">") points = np.fromfile(f, count=num_points * 3, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() return points.reshape((num_points, 3)) def _read_int_data(f, is_ascii, num_items, dtype): if is_ascii: c = np.fromfile(f, count=num_items, sep=" ", dtype=dtype) else: dtype = dtype.newbyteorder(">") c = np.fromfile(f, count=num_items, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError("Expected newline") return c def _read_cell_types(f, is_ascii, num_items): if is_ascii: ct = np.fromfile(f, count=int(num_items), sep=" ", dtype=int) else: # binary ct = np.fromfile(f, count=int(num_items), dtype=">i4") line = f.readline().decode() # Sometimes, there's no newline at the end if line.strip() != "": raise ReadError() return ct def _read_scalar_field(f, num_data, split, is_ascii): data_name = split[1] data_type = split[2].lower() try: num_comp = int(split[3]) except IndexError: num_comp = 1 # The standard says: # > The parameter numComp must range between (1,4) inclusive; [...] if not (0 < num_comp < 5): raise ReadError("The parameter numComp must range between (1,4) inclusive") dtype = np.dtype(vtk_to_numpy_dtype_name[data_type]) lt, _ = f.readline().decode().split() if lt.upper() != "LOOKUP_TABLE": raise ReadError() if is_ascii: data = np.fromfile(f, count=num_data * num_comp, sep=" ", dtype=dtype) else: # Binary data is big endian, see # . dtype = dtype.newbyteorder(">") data = np.fromfile(f, count=num_data * num_comp, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() data = data.reshape(-1, num_comp) return {data_name: data} def _read_field(f, num_data, split, shape, is_ascii): data_name = split[1] data_type = split[2].lower() dtype = np.dtype(vtk_to_numpy_dtype_name[data_type]) # prod() # k = reduce((lambda x, y: x * y), shape) if is_ascii: data = np.fromfile(f, count=k * num_data, sep=" ", dtype=dtype) else: # Binary data is big endian, see # . dtype = dtype.newbyteorder(">") data = np.fromfile(f, count=k * num_data, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() data = data.reshape(-1, *shape) return {data_name: data} def _read_fields(f, num_fields, is_ascii): data = {} for _ in range(num_fields): line = f.readline().decode().split() if line[0] == "METADATA": _skip_meta(f) name, shape0, shape1, data_type = f.readline().decode().split() else: name, shape0, shape1, data_type = line shape0 = int(shape0) shape1 = int(shape1) dtype = np.dtype(vtk_to_numpy_dtype_name[data_type.lower()]) if is_ascii: dat = np.fromfile(f, count=shape0 * shape1, sep=" ", dtype=dtype) else: # Binary data is big endian, see # . dtype = dtype.newbyteorder(">") dat = np.fromfile(f, count=shape0 * shape1, dtype=dtype) line = f.readline().decode() if line != "\n": raise ReadError() if shape0 != 1: dat = dat.reshape((shape1, shape0)) data[name] = dat return data def _skip_meta(f): # skip possible metadata # https://vtk.org/doc/nightly/html/IOLegacyInformationFormat.html while True: line = f.readline().decode().strip() if not line: # end of metadata is a blank line break def _pad(array): return np.pad(array, ((0, 0), (0, 1)), "constant") def write(filename, mesh, binary=True): if mesh.points.shape[1] == 2: warn( "VTK requires 3D points, but 2D points given. " "Appending 0 third component." ) points = _pad(mesh.points) else: points = mesh.points if mesh.point_data: for name, values in mesh.point_data.items(): if len(values.shape) == 2 and values.shape[1] == 2: warn( "VTK requires 3D vectors, but 2D vectors given. " f"Appending 0 third component to {name}." ) mesh.point_data[name] = _pad(values) for name, data in mesh.cell_data.items(): for k, values in enumerate(data): if len(values.shape) == 2 and values.shape[1] == 2: warn( "VTK requires 3D vectors, but 2D vectors given. " f"Appending 0 third component to {name}." ) data[k] = _pad(data[k]) if not binary: warn("VTK ASCII files are only meant for debugging.") if mesh.point_sets: info( "VTK format cannot write point_sets. Converting them to point_data...", highlight=False, ) key, _ = join_strings(list(mesh.point_sets.keys())) key, _ = replace_space(key) mesh.point_sets_to_data(key) if mesh.cell_sets: info( "VTK format cannot write cell_sets. Converting them to cell_data...", highlight=False, ) key, _ = join_strings(list(mesh.cell_sets.keys())) key, _ = replace_space(key) mesh.cell_sets_to_data(key) with open_file(filename, "wb") as f: f.write(b"# vtk DataFile Version 5.1\n") f.write(f"written by meshio v{__version__}\n".encode()) f.write(("BINARY\n" if binary else "ASCII\n").encode()) f.write(b"DATASET UNSTRUCTURED_GRID\n") # write points and cells _write_points(f, points, binary) _write_cells(f, mesh.cells, binary) # write point data if mesh.point_data: num_points = mesh.points.shape[0] f.write(f"POINT_DATA {num_points}\n".encode()) _write_field_data(f, mesh.point_data, binary) # write cell data if mesh.cell_data: total_num_cells = sum(len(c.data) for c in mesh.cells) f.write(f"CELL_DATA {total_num_cells}\n".encode()) _write_field_data(f, mesh.cell_data, binary) def _write_points(f, points, binary): dtype = numpy_to_vtk_dtype[points.dtype.name] f.write(f"POINTS {len(points)} {dtype}\n".encode()) if binary: # Binary data must be big endian, see # . # if points.dtype.byteorder == "<" or ( # points.dtype.byteorder == "=" and sys.byteorder == "little" # ): # logging.warn("Converting to new byte order") points.astype(points.dtype.newbyteorder(">")).tofile(f, sep="") else: # ascii points.tofile(f, sep=" ") f.write(b"\n") def _write_cells(f, cells, binary): total_num_cells = sum(len(c.data) for c in cells) total_num_idx = sum(c.data.size for c in cells) f.write(f"CELLS {total_num_cells + 1} {total_num_idx}\n".encode()) # offsets offsets = [[0]] k = 0 for cell_block in cells: m, n = cell_block.data.shape offsets.append(np.arange(k + n, k + (m + 1) * n, n)) k = offsets[-1][-1] offsets = np.concatenate(offsets) if binary: f.write(b"OFFSETS vtktypeint64\n") # force big-endian and int64 offsets.astype(">i8").tofile(f, sep="") f.write(b"\n") f.write(b"CONNECTIVITY vtktypeint64\n") for cell_block in cells: d = cell_block.data cell_idx = meshio_to_vtk_order(cell_block.type) if cell_idx is not None: d = d[:, cell_idx] # force big-endian and int64 d.astype(">i8").tofile(f, sep="") f.write(b"\n") else: # ascii f.write(b"OFFSETS vtktypeint64\n") offsets.tofile(f, sep="\n") f.write(b"\n") f.write(b"CONNECTIVITY vtktypeint64\n") for cell_block in cells: d = cell_block.data cell_idx = meshio_to_vtk_order(cell_block.type) if cell_idx is not None: d = d[:, cell_idx] d.tofile(f, sep="\n") f.write(b"\n") # write cell types f.write(f"CELL_TYPES {total_num_cells}\n".encode()) if binary: for c in cells: vtk_type = meshio_to_vtk_type[c.type] np.full(len(c.data), vtk_type, dtype=np.dtype(">i4")).tofile(f, sep="") f.write(b"\n") else: # ascii for c in cells: vtk_type = meshio_to_vtk_type[c.type] np.full(len(c.data), vtk_type).tofile(f, sep="\n") f.write(b"\n") def _write_field_data(f, data, binary): f.write((f"FIELD FieldData {len(data)}\n").encode()) for name, values in data.items(): if isinstance(values, list): values = np.concatenate(values) if len(values.shape) == 1: num_tuples = values.shape[0] num_components = 1 else: num_tuples = values.shape[0] num_components = values.shape[1] if " " in name: raise WriteError(f"VTK doesn't support spaces in field names ('{name}').") vtk_dtype = numpy_to_vtk_dtype[values.dtype.name] f.write(f"{name} {num_components} {num_tuples} {vtk_dtype}\n".encode()) if binary: values.astype(values.dtype.newbyteorder(">")).tofile(f, sep="") else: # ascii values.tofile(f, sep=" ") # np.savetxt(f, points) f.write(b"\n") src/meshio/vtu/000077500000000000000000000000001456244072500137605ustar00rootroot00000000000000src/meshio/vtu/__init__.py000066400000000000000000000000731456244072500160710ustar00rootroot00000000000000from ._vtu import read, write __all__ = ["read", "write"] src/meshio/vtu/_vtu.py000066400000000000000000001022041456244072500153060ustar00rootroot00000000000000""" I/O for VTU. """ import base64 import re import sys import zlib import numpy as np from ..__about__ import __version__ from .._common import info, join_strings, raw_from_cell_data, replace_space, warn from .._exceptions import CorruptionError, ReadError from .._helpers import register_format from .._mesh import CellBlock, Mesh from .._vtk_common import meshio_to_vtk_order, meshio_to_vtk_type, vtk_cells_from_data # Paraview 5.8.1's built-in Python doesn't have lzma. try: import lzma except ModuleNotFoundError: lzma = None def num_bytes_to_num_base64_chars(num_bytes): # Rounding up in integer division works by double negation since Python # always rounds down. return -(-num_bytes // 3) * 4 def _polyhedron_cells_from_data(offsets, faces, faceoffsets, cell_data_raw): # In general the number of faces will vary between cells, and the # number of nodes vary between faces for each cell. The information # will be stored as a List (one item per cell) of lists (one item # per face of the cell) of np-arrays of node indices. cells = {} cell_data = {} # The data format for face-cells is: # num_faces_cell_0, # num_nodes_face_0, node_ind_0, node_ind_1, .. # num_nodes_face_1, node_ind_0, node_ind_1, .. # ... # num_faces_cell_1, # ... # See https://vtk.org/Wiki/VTK/Polyhedron_Support for more. # The faceoffsets describes the end of the face description for each # cell. Switch faceoffsets to give start points, not end points faceoffsets = np.append([0], faceoffsets[:-1]) # Double loop over cells then faces. # This will be slow, but seems necessary to cover all cases for cell_start in faceoffsets: num_faces_this_cell = faces[cell_start] faces_this_cell = [] next_face = cell_start + 1 for _ in range(num_faces_this_cell): num_nodes_this_face = faces[next_face] faces_this_cell.append( np.array( faces[next_face + 1 : (next_face + num_nodes_this_face + 1)], dtype=int, ) ) # Increase by number of nodes just read, plus the item giving # number of nodes per face next_face += num_nodes_this_face + 1 # Done with this cell # Find number of nodes for this cell num_nodes_this_cell = np.unique(np.hstack([v for v in faces_this_cell])).size key = f"polyhedron{num_nodes_this_cell}" if key not in cells.keys(): cells[key] = [] cells[key].append(faces_this_cell) # The cells will be assigned to blocks according to their number of nodes. # This is potentially a reordering, compared to the ordering in faces. # Cell data must be reorganized accordingly. # Start of the cell-node relations start_cn = np.hstack((0, offsets)) size = np.diff(start_cn) # Loop over all cell sizes, find all cells with this size, and store # cell data. for sz in np.unique(size): # Cells with this number of nodes. items = np.where(size == sz)[0] # Store cell data for this set of cells for name, d in cell_data_raw.items(): if name not in cell_data: cell_data[name] = [] cell_data[name].append(d[items]) return cells, cell_data def _organize_cells(point_offsets, cells, cell_data_raw): if len(point_offsets) != len(cells): raise ReadError("Inconsistent data!") out_cells = [] # IMPLEMENTATION NOTE: The treatment of polyhedral cells is quite a bit different # from the other cells; moreover, there are some strong (?) assumptions on such # cells. The processing of such cells is therefore moved to a dedicated function for # the time being, while all other cell types are treated by the same function. # There are still similarities between processing of polyhedral and the rest, so it # may be possible to unify the implementations at a later stage. # Check if polyhedral cells are present. polyhedral_mesh = False for c in cells: if np.any(c["types"] == 42): # vtk type 42 is polyhedral polyhedral_mesh = True break if polyhedral_mesh: # The current implementation assumes a single set of cells, and cannot mix # polyhedral cells with other cell types. It may be possible to do away with # these limitations, but for the moment, this is what is available. if len(cells) > 1: raise ValueError("Implementation assumes single set of cells") if np.any(cells[0]["types"] != 42): raise ValueError("Cannot handle combinations of polyhedra with other cells") # Polyhedra are specified by their faces and faceoffsets; see the function # _polyhedron_cells_from_data for more information. faces = cells[0]["faces"] faceoffsets = cells[0]["faceoffsets"] cls, cell_data = _polyhedron_cells_from_data( cells[0]["offsets"], faces, faceoffsets, cell_data_raw[0] ) # Organize polyhedra in cell blocks according to the number of nodes per cell. for tp, c in cls.items(): out_cells.append(CellBlock(tp, c)) else: for offset, cls, cdr in zip(point_offsets, cells, cell_data_raw): cls, cell_data = vtk_cells_from_data( cls["connectivity"].ravel(), cls["offsets"].ravel(), cls["types"].ravel(), cdr, ) for c in cls: out_cells.append(CellBlock(c.type, c.data + offset)) return out_cells, cell_data def get_grid(root): grid = None appended_data = None for c in root: if c.tag == "UnstructuredGrid": if grid is not None: raise ReadError("More than one UnstructuredGrid found.") grid = c else: if c.tag != "AppendedData": raise ReadError(f"Unknown main tag '{c.tag}'.") if appended_data is not None: raise ReadError("More than one AppendedData section found.") if c.attrib["encoding"] != "base64": raise ReadError("") appended_data = c.text.strip() # The appended data always begins with a (meaningless) underscore. if appended_data[0] != "_": raise ReadError() appended_data = appended_data[1:] if grid is None: raise ReadError("No UnstructuredGrid found.") return grid, appended_data def _parse_raw_binary(filename): from xml.etree import ElementTree as ET with open(filename, "rb") as f: raw = f.read() try: res = re.search(re.compile(b']+(?:">)'), raw) assert res is not None i_start = res.end() i_stop = raw.find(b"") except Exception: raise ReadError() header = raw[:i_start].decode() footer = raw[i_stop:].decode() data = raw[i_start:i_stop].split(b"_", 1)[1].rsplit(b"\n", 1)[0] root = ET.fromstring(header + footer) dtype = vtu_to_numpy_type[root.get("header_type", "UInt32")] if "byte_order" in root.attrib: dtype = dtype.newbyteorder( "<" if root.get("byte_order") == "LittleEndian" else ">" ) appended_data_tag = root.find("AppendedData") assert appended_data_tag is not None appended_data_tag.set("encoding", "base64") compressor = root.get("compressor") if compressor is None: arrays = "" i = 0 while i < len(data): # The following find() runs into issues if offset is padded with spaces, see # . It works in ParaView. # Unfortunately, Python's built-in XML tree can't handle regexes, see # . da_tag = root.find(f".//DataArray[@offset='{i}']") if da_tag is None: raise RuntimeError(f"Could not find .//DataArray[@offset='{i}']") da_tag.set("offset", str(len(arrays))) block_size = int(np.frombuffer(data[i : i + dtype.itemsize], dtype)[0]) arrays += base64.b64encode( data[i : i + block_size + dtype.itemsize] ).decode() i += block_size + dtype.itemsize else: c = {"vtkLZMADataCompressor": lzma, "vtkZLibDataCompressor": zlib}[compressor] root.attrib.pop("compressor") # raise ReadError("Compressed raw binary VTU files not supported.") arrays = "" i = 0 while i < len(data): da_tag = root.find(f".//DataArray[@offset='{i}']") assert da_tag is not None da_tag.set("offset", str(len(arrays))) num_blocks = int(np.frombuffer(data[i : i + dtype.itemsize], dtype)[0]) num_header_items = 3 + num_blocks num_header_bytes = num_header_items * dtype.itemsize header = np.frombuffer(data[i : i + num_header_bytes], dtype) block_data = b"" j = 0 for k in range(num_blocks): block_size = int(header[k + 3]) block_data += c.decompress( data[ i + j + num_header_bytes : i + j + block_size + num_header_bytes ] ) j += block_size block_size = np.array([len(block_data)]).astype(dtype).tobytes() arrays += base64.b64encode(block_size + block_data).decode() i += j + num_header_bytes appended_data_tag.text = "_" + arrays return root vtu_to_numpy_type = { "Float32": np.dtype(np.float32), "Float64": np.dtype(np.float64), "Int8": np.dtype(np.int8), "Int16": np.dtype(np.int16), "Int32": np.dtype(np.int32), "Int64": np.dtype(np.int64), "UInt8": np.dtype(np.uint8), "UInt16": np.dtype(np.uint16), "UInt32": np.dtype(np.uint32), "UInt64": np.dtype(np.uint64), } numpy_to_vtu_type = {v: k for k, v in vtu_to_numpy_type.items()} class VtuReader: """Helper class for reading VTU files. Some properties are global to the file (e.g., byte_order), and instead of passing around these parameters, make them properties of this class. """ def __init__(self, filename): # noqa: C901 from xml.etree import ElementTree as ET parser = ET.XMLParser() try: tree = ET.parse(str(filename), parser) root = tree.getroot() except ET.ParseError: root = _parse_raw_binary(str(filename)) if root.tag != "VTKFile": raise ReadError(f"Expected tag 'VTKFile', found {root.tag}") if root.attrib["type"] != "UnstructuredGrid": tpe = root.attrib["type"] raise ReadError(f"Expected type UnstructuredGrid, found {tpe}") if "version" in root.attrib: version = root.attrib["version"] if version not in ["0.1", "1.0"]: raise ReadError(f"Unknown VTU file version '{version}'.") # fix empty NumberOfComponents attributes as produced by Firedrake for da_tag in root.findall(".//DataArray[@NumberOfComponents='']"): da_tag.attrib.pop("NumberOfComponents") if "compressor" in root.attrib: assert root.attrib["compressor"] in [ "vtkLZMADataCompressor", "vtkZLibDataCompressor", ] self.compression = root.attrib["compressor"] else: self.compression = None self.header_type = ( root.attrib["header_type"] if "header_type" in root.attrib else "UInt32" ) try: self.byte_order = root.attrib["byte_order"] if self.byte_order not in ["LittleEndian", "BigEndian"]: raise ReadError(f"Unknown byte order '{self.byte_order}'.") except KeyError: self.byte_order = None grid, self.appended_data = get_grid(root) pieces = [] field_data = {} for c in grid: if c.tag == "Piece": pieces.append(c) elif c.tag == "FieldData": # TODO test field data for data_array in c: field_data[data_array.attrib["Name"]] = self.read_data(data_array) else: raise ReadError(f"Unknown grid subtag '{c.tag}'.") if not pieces: raise ReadError("No Piece found.") points = [] cells = [] point_data = [] cell_data_raw = [] for piece in pieces: piece_cells = {} piece_point_data = {} piece_cell_data_raw = {} num_points = int(piece.attrib["NumberOfPoints"]) num_cells = int(piece.attrib["NumberOfCells"]) for child in piece: if child.tag == "Points": data_arrays = list(child) if len(data_arrays) != 1: raise ReadError() data_array = data_arrays[0] if data_array.tag != "DataArray": raise ReadError() pts = self.read_data(data_array) num_components = int(data_array.attrib["NumberOfComponents"]) points.append(pts.reshape(num_points, num_components)) elif child.tag == "Cells": for data_array in child: if data_array.tag != "DataArray": raise ReadError() piece_cells[data_array.attrib["Name"]] = self.read_data( data_array ) if len(piece_cells["offsets"]) != num_cells: raise ReadError() if len(piece_cells["types"]) != num_cells: raise ReadError() cells.append(piece_cells) elif child.tag == "PointData": for c in child: if c.tag != "DataArray": raise ReadError() try: piece_point_data[c.attrib["Name"]] = self.read_data(c) except CorruptionError as e: warn(e.args[0] + " Skipping.") point_data.append(piece_point_data) elif child.tag == "CellData": for c in child: if c.tag != "DataArray": raise ReadError() piece_cell_data_raw[c.attrib["Name"]] = self.read_data(c) cell_data_raw.append(piece_cell_data_raw) else: raise ReadError(f"Unknown tag '{child.tag}'.") if not cell_data_raw: cell_data_raw = [{}] * len(cells) if len(cell_data_raw) != len(cells): raise ReadError() point_offsets = np.cumsum([0] + [pts.shape[0] for pts in points][:-1]) # Now merge across pieces if not points: raise ReadError() self.points = np.concatenate(points) if point_data: self.point_data = { key: np.concatenate([pd[key] for pd in point_data]) for key in point_data[0] } else: self.point_data = None self.cells, self.cell_data = _organize_cells( point_offsets, cells, cell_data_raw ) self.field_data = field_data def read_uncompressed_binary(self, data, dtype): byte_string = base64.b64decode(data) # the first item is the total_num_bytes, given in header_dtype header_dtype = vtu_to_numpy_type[self.header_type] if self.byte_order is not None: header_dtype = header_dtype.newbyteorder( "<" if self.byte_order == "LittleEndian" else ">" ) num_header_bytes = np.dtype(header_dtype).itemsize total_num_bytes = np.frombuffer(byte_string[:num_header_bytes], header_dtype)[0] # Check if block size was decoded separately # (so decoding stopped after block size due to padding) if len(byte_string) == num_header_bytes: header_len = len(base64.b64encode(byte_string)) byte_string = base64.b64decode(data[header_len:]) else: byte_string = byte_string[num_header_bytes:] # Read the block data; multiple blocks possible here? if self.byte_order is not None: dtype = dtype.newbyteorder( "<" if self.byte_order == "LittleEndian" else ">" ) return np.frombuffer(byte_string[:total_num_bytes], dtype=dtype) def read_compressed_binary(self, data, dtype): # first read the block size; it determines the size of the header header_dtype = vtu_to_numpy_type[self.header_type] if self.byte_order is not None: header_dtype = header_dtype.newbyteorder( "<" if self.byte_order == "LittleEndian" else ">" ) num_bytes_per_item = np.dtype(header_dtype).itemsize num_chars = num_bytes_to_num_base64_chars(num_bytes_per_item) byte_string = base64.b64decode(data[:num_chars])[:num_bytes_per_item] num_blocks = np.frombuffer(byte_string, header_dtype)[0] # read the entire header num_header_items = 3 + int(num_blocks) num_header_bytes = num_bytes_per_item * num_header_items num_header_chars = num_bytes_to_num_base64_chars(num_header_bytes) byte_string = base64.b64decode(data[:num_header_chars]) header = np.frombuffer(byte_string, header_dtype) # num_blocks = header[0] # max_uncompressed_block_size = header[1] # last_compressed_block_size = header[2] block_sizes = header[3:] # Read the block data byte_array = base64.b64decode(data[num_header_chars:]) if self.byte_order is not None: dtype = dtype.newbyteorder( "<" if self.byte_order == "LittleEndian" else ">" ) byte_offsets = np.empty(block_sizes.shape[0] + 1, dtype=block_sizes.dtype) byte_offsets[0] = 0 np.cumsum(block_sizes, out=byte_offsets[1:]) assert self.compression is not None c = {"vtkLZMADataCompressor": lzma, "vtkZLibDataCompressor": zlib}[ self.compression ] # process the compressed data block_data = np.concatenate( [ np.frombuffer( c.decompress(byte_array[byte_offsets[k] : byte_offsets[k + 1]]), dtype=dtype, ) for k in range(num_blocks) ] ) return block_data def read_data(self, c): fmt = c.attrib["format"] if "format" in c.attrib else "ascii" data_type = c.attrib["type"] try: dtype = vtu_to_numpy_type[data_type] except KeyError: raise ReadError(f"Illegal data type '{data_type}'.") if fmt == "ascii": # ascii if c.text.strip() == "": # https://github.com/numpy/numpy/issues/18435 data = np.empty((0,), dtype=dtype) else: data = np.fromstring(c.text, dtype=dtype, sep=" ") elif fmt == "binary": reader = ( self.read_uncompressed_binary if self.compression is None else self.read_compressed_binary ) data = reader(c.text.strip(), dtype) elif fmt == "appended": offset = int(c.attrib["offset"]) reader = ( self.read_uncompressed_binary if self.compression is None else self.read_compressed_binary ) assert self.appended_data is not None data = reader(self.appended_data[offset:], dtype) else: raise ReadError(f"Unknown data format '{fmt}'.") if "NumberOfComponents" in c.attrib: nc = int(c.attrib["NumberOfComponents"]) try: data = data.reshape(-1, nc) except ValueError: name = c.attrib["Name"] raise CorruptionError( "VTU file corrupt. " + f"The size of the data array '{name}' is {data.size} " + f"which doesn't fit the number of components {nc}." ) return data def read(filename): reader = VtuReader(filename) return Mesh( reader.points, reader.cells, point_data=reader.point_data, cell_data=reader.cell_data, field_data=reader.field_data, ) def _chunk_it(array, n): k = 0 while k * n < len(array): yield array[k * n : (k + 1) * n] k += 1 def write(filename, mesh, binary=True, compression="zlib", header_type=None): # Writing XML with an etree required first transforming the (potentially large) # arrays into string, which are much larger in memory still. This makes this writer # very memory hungry. See . from .._cxml import etree as ET # Check if the mesh contains polyhedral cells, this will require special treatment # in certain places. is_polyhedron_grid = False for c in mesh.cells: if c.type.startswith("polyhedron"): is_polyhedron_grid = True break # The current implementation cannot mix polyhedral cells with other cell types. # To write such meshes, represent all cells as polyhedra. if is_polyhedron_grid: for c in mesh.cells: if c.type[:10] != "polyhedron": raise ValueError( "VTU export cannot mix polyhedral cells with other cell types" ) if not binary: warn("VTU ASCII files are only meant for debugging.") if mesh.points.shape[1] == 2: warn( "VTU requires 3D points, but 2D points given. " "Appending 0 third component." ) points = np.column_stack([mesh.points, np.zeros_like(mesh.points[:, 0])]) else: points = mesh.points if mesh.point_sets: info( "VTU format cannot write point_sets. Converting them to point_data...", highlight=False, ) key, _ = join_strings(list(mesh.point_sets.keys())) key, _ = replace_space(key) mesh.point_sets_to_data(key) if mesh.cell_sets: info( "VTU format cannot write cell_sets. Converting them to cell_data...", highlight=False, ) key, _ = join_strings(list(mesh.cell_sets.keys())) key, _ = replace_space(key) mesh.cell_sets_to_data(key) vtk_file = ET.Element( "VTKFile", type="UnstructuredGrid", version="0.1", # Use the native endianness. Not strictly necessary, but this simplifies things # a bit. byte_order=("LittleEndian" if sys.byteorder == "little" else "BigEndian"), ) if header_type is None: header_type = "UInt32" else: vtk_file.set("header_type", header_type) assert header_type is not None if binary and compression: # TODO lz4 compressions = { "lzma": "vtkLZMADataCompressor", "zlib": "vtkZLibDataCompressor", } assert compression in compressions vtk_file.set("compressor", compressions[compression]) # swap the data to match the system byteorder # Don't use byteswap to make sure that the dtype is changed; see # . points = points.astype(points.dtype.newbyteorder("="), copy=False) for k, cell_block in enumerate(mesh.cells): cell_type = cell_block.type data = cell_block.data # Treatment of polyhedra is different from other types if is_polyhedron_grid: new_cell_info = [] for cell_info in data: new_face_info = [] for face_info in cell_info: face_info = np.asarray(face_info) new_face_info.append( face_info.astype(face_info.dtype.newbyteorder("="), copy=False) ) new_cell_info.append(new_face_info) mesh.cells[k] = CellBlock(cell_type, new_cell_info) else: mesh.cells[k] = CellBlock( cell_type, data.astype(data.dtype.newbyteorder("="), copy=False) ) for key, data in mesh.point_data.items(): mesh.point_data[key] = data.astype(data.dtype.newbyteorder("="), copy=False) for data in mesh.cell_data.values(): for k, dat in enumerate(data): data[k] = dat.astype(dat.dtype.newbyteorder("="), copy=False) for key, data in mesh.field_data.items(): mesh.field_data[key] = data.astype(data.dtype.newbyteorder("="), copy=False) def numpy_to_xml_array(parent, name, data): vtu_type = numpy_to_vtu_type[data.dtype] fmt = "{:.11e}" if vtu_type.startswith("Float") else "{:d}" da = ET.SubElement(parent, "DataArray", type=vtu_type, Name=name) if len(data.shape) == 2: da.set("NumberOfComponents", f"{data.shape[1]}") def text_writer_compressed(f): max_block_size = 32768 data_bytes = data.tobytes() # round up num_blocks = -int(-len(data_bytes) // max_block_size) last_block_size = len(data_bytes) - (num_blocks - 1) * max_block_size # It's too bad that we have to keep all blocks in memory. This is # necessary because the header, written first, needs to know the # lengths of all blocks. Also, the blocks are encoded _after_ having # been concatenated. c = {"lzma": lzma, "zlib": zlib}[compression] compressed_blocks = [ # This compress is the slowest part of the writer c.compress(block) for block in _chunk_it(data_bytes, max_block_size) ] # collect header header = np.array( [num_blocks, max_block_size, last_block_size] + [len(b) for b in compressed_blocks], dtype=vtu_to_numpy_type[header_type], ) f.write(base64.b64encode(header.tobytes()).decode()) f.write(base64.b64encode(b"".join(compressed_blocks)).decode()) def text_writer_uncompressed(f): data_bytes = data.tobytes() # collect header header = np.array(len(data_bytes), dtype=vtu_to_numpy_type[header_type]) f.write(base64.b64encode(header.tobytes() + data_bytes).decode()) def text_writer_ascii(f): # This write() loop is the bottleneck for the write. Alternatives: # savetxt is super slow: # np.savetxt(f, data.reshape(-1), fmt=fmt) # joining and writing is a bit faster, but consumes huge amounts of # memory: # f.write("\n".join(map(fmt.format, data.reshape(-1)))) for item in data.reshape(-1): f.write((fmt + "\n").format(item)) if binary: da.set("format", "binary") da.text_writer = ( text_writer_compressed if compression else text_writer_uncompressed ) else: da.set("format", "ascii") da.text_writer = text_writer_ascii def _polyhedron_face_cells(face_cells): # Define the faces of each cell on the format specified for VTU Polyhedron # cells. These are defined in Mesh.polyhedron_faces, as block data. The block # consists of a nested list (outer list represents cell, inner is faces for this # cells), where the items of the inner list are the nodes of specific faces. # # The output format is specified at https://vtk.org/Wiki/VTK/Polyhedron_Support # Initialize array for size of data per cell. data_size_per_cell = np.zeros(len(face_cells), dtype=int) # The data itself is of unknown size, and cannot be initialized data = [] for ci, cell in enumerate(face_cells): # Number of faces for this cell data.append(len(cell)) for face in cell: # Number of nodes for this face data.append(face.size) # The nodes themselves data += face.tolist() data_size_per_cell[ci] = len(data) # The returned data corresponds to the faces and faceoffsets fields in the # vtu polyhedron data format return data, data_size_per_cell.tolist() comment = ET.Comment(f"This file was created by meshio v{__version__}") vtk_file.insert(1, comment) grid = ET.SubElement(vtk_file, "UnstructuredGrid") total_num_cells = sum(len(c.data) for c in mesh.cells) piece = ET.SubElement( grid, "Piece", NumberOfPoints=f"{len(points)}", NumberOfCells=f"{total_num_cells}", ) # points if points is not None: pts = ET.SubElement(piece, "Points") numpy_to_xml_array(pts, "Points", points) if mesh.cells is not None and len(mesh.cells) > 0: cls = ET.SubElement(piece, "Cells") faces = None faceoffsets = None if is_polyhedron_grid: # The VTK polyhedron format requires both Cell-node connectivity, and a # definition of faces. The cell-node relation must be recoved from the # cell-face-nodes currently in CellBlocks. # NOTE: If polyhedral cells are implemented for more mesh types, this code # block may be useful for those as well. con = [] num_nodes_per_cell = [] for block in mesh.cells: for cell in block.data: nodes_this_cell = [] for face in cell: nodes_this_cell += face.tolist() unique_nodes = np.unique(nodes_this_cell).tolist() con += unique_nodes num_nodes_per_cell.append(len(unique_nodes)) connectivity = np.array(con) # offsets = np.hstack(([0], np.cumsum(num_nodes_per_cell)[:-1])) offsets = np.cumsum(num_nodes_per_cell) # Initialize data structures for polyhedral cells faces = [] faceoffsets = [] else: # create connectivity, offset, type arrays connectivity = [] for v in mesh.cells: d = v.data new_order = meshio_to_vtk_order(v.type) if new_order is not None: d = d[:, new_order] connectivity.append(d.flatten()) connectivity = np.concatenate(connectivity) # offset (points to the first element of the next cell) offsets = [ v.data.shape[1] * np.arange(1, v.data.shape[0] + 1, dtype=connectivity.dtype) for v in mesh.cells ] for k in range(1, len(offsets)): offsets[k] += offsets[k - 1][-1] offsets = np.concatenate(offsets) # types types_array = [] for cell_block in mesh.cells: key = cell_block.type # some adaptions for polyhedron if key.startswith("polyhedron"): # Get face-cell relation on the vtu format. See comments in helper # function for more information of how to specify this. faces_loc, faceoffsets_loc = _polyhedron_face_cells(cell_block.data) # Adjust offsets to global numbering assert faceoffsets is not None if len(faceoffsets) > 0: faceoffsets_loc = [fi + faceoffsets[-1] for fi in faceoffsets_loc] assert faces is not None faces += faces_loc faceoffsets += faceoffsets_loc key = "polyhedron" types_array.append(np.full(len(cell_block), meshio_to_vtk_type[key])) types = np.concatenate( types_array # [np.full(len(v), meshio_to_vtk_type[k]) for k, v in mesh.cells] ) numpy_to_xml_array(cls, "connectivity", connectivity) numpy_to_xml_array(cls, "offsets", offsets) numpy_to_xml_array(cls, "types", types) if is_polyhedron_grid: # Also store face-node relation numpy_to_xml_array(cls, "faces", np.array(faces, dtype=int)) numpy_to_xml_array(cls, "faceoffsets", np.array(faceoffsets, dtype=int)) if mesh.point_data: pd = ET.SubElement(piece, "PointData") for name, data in mesh.point_data.items(): numpy_to_xml_array(pd, name, data) if mesh.cell_data: cd = ET.SubElement(piece, "CellData") for name, data in raw_from_cell_data(mesh.cell_data).items(): numpy_to_xml_array(cd, name, data) # write_xml(filename, vtk_file, pretty_xml) tree = ET.ElementTree(vtk_file) tree.write(filename) register_format("vtu", [".vtu"], read, {"vtu": write}) src/meshio/wkt/000077500000000000000000000000001456244072500137475ustar00rootroot00000000000000src/meshio/wkt/__init__.py000066400000000000000000000000731456244072500160600ustar00rootroot00000000000000from ._wkt import read, write __all__ = ["read", "write"] src/meshio/wkt/_wkt.py000066400000000000000000000054051456244072500152710ustar00rootroot00000000000000import re from collections import OrderedDict from io import StringIO import numpy as np from .._common import warn from .._exceptions import ReadError from .._files import open_file from .._helpers import register_format from .._mesh import CellBlock, Mesh float_pattern = r"[+-]?(?:\d+\.?\d*|\d*\.?\d+)" float_re = re.compile(float_pattern) point_pattern = r"{0}\s+{0}\s+{0}(?:\s+{0})?".format(float_pattern) point_re = re.compile(point_pattern) triangle_pattern = r"\(\s*\(\s*({})\s*\)\s*\)".format( r"\s*,\s*".join(point_pattern for _ in range(4)) ) triangle_re = re.compile(triangle_pattern) tin_pattern = rf"TIN\s*\((?:\s*{triangle_pattern}\s*,?)*\s*\)" tin_re = re.compile(tin_pattern) def read_str(s): s = s.strip() tin_match = tin_re.match(s) if tin_match is None: raise ReadError("Invalid WKT TIN") point_idxs = OrderedDict() tri_idxs = [] for tri_match in triangle_re.finditer(tin_match.group()): tri_point_idxs = [] for point_match in point_re.finditer(tri_match.group()): point = [] for float_match in float_re.finditer(point_match.group()): point.append(float(float_match.group())) point = tuple(point) if point not in point_idxs: point_idxs[point] = len(point_idxs) tri_point_idxs.append(point_idxs[point]) if tri_point_idxs[-1] != tri_point_idxs[0]: raise ValueError("Triangle is not a closed linestring") tri_idxs.append(tri_point_idxs[:-1]) try: point_arr = np.array(list(point_idxs), np.float64) except ValueError as e: if len({len(p) for p in point_idxs}) > 1: raise ReadError("Points have mixed dimensionality") else: raise e tri_arr = np.array(tri_idxs, np.uint64) return Mesh(point_arr, [CellBlock("triangle", tri_arr)]) def arr_to_str(arr): return " ".join(str(item) for item in arr) def read(filename): with open_file(filename) as f: return read_str(f.read()) def write(filename, mesh): with open_file(filename, "w") as f: write_buffer(f, mesh) def write_buffer(f, mesh): skip = [c for c in mesh.cells if c.type != "triangle"] if skip: warn('WTK only supports triangle cells. Skipping {", ".join(skip)}.') triangles = mesh.get_cells_type("triangle") f.write("TIN (") joiner = "" for tri_points in mesh.points[triangles]: f.write( "{0}(({1}, {2}, {3}, {1}))".format( joiner, *(arr_to_str(p) for p in tri_points) ) ) joiner = ", " f.write(")") def write_str(mesh): buf = StringIO() write_buffer(buf, mesh) buf.seek(0) return buf.read() register_format("wkt", [".wkt"], read, {"wkt": write}) src/meshio/xdmf/000077500000000000000000000000001456244072500141005ustar00rootroot00000000000000src/meshio/xdmf/__init__.py000066400000000000000000000003471456244072500162150ustar00rootroot00000000000000""" I/O for XDMF. https://xdmf.org/index.php/XDMF_Model_and_Format """ from .main import read, write from .time_series import TimeSeriesReader, TimeSeriesWriter __all__ = ["read", "write", "TimeSeriesWriter", "TimeSeriesReader"] src/meshio/xdmf/common.py000066400000000000000000000124741456244072500157520ustar00rootroot00000000000000import numpy as np from .._exceptions import ReadError from .._mesh import CellBlock numpy_to_xdmf_dtype = { "int8": ("Int", "1"), "int16": ("Int", "2"), "int32": ("Int", "4"), "int64": ("Int", "8"), "uint8": ("UInt", "1"), "uint16": ("UInt", "2"), "uint32": ("UInt", "4"), "uint64": ("UInt", "8"), "float32": ("Float", "4"), "float64": ("Float", "8"), } xdmf_to_numpy_type = {v: k for k, v in numpy_to_xdmf_dtype.items()} dtype_to_format_string = { "int32": "%d", "int64": "%d", "uint32": "%d", "uint64": "%d", "float32": "%.7e", "float64": "%.16e", } # See # # # for XDMF types. # There appears to be no particular consistency, so allow for different # alternatives as well. meshio_to_xdmf_type = { "vertex": ["Polyvertex"], "line": ["Polyline"], "line3": ["Edge_3"], "quad": ["Quadrilateral"], "quad8": ["Quadrilateral_8", "Quad_8"], "quad9": ["Quadrilateral_9", "Quad_9"], "pyramid": ["Pyramid"], "pyramid13": ["Pyramid_13"], "tetra": ["Tetrahedron"], "triangle": ["Triangle"], "triangle6": ["Triangle_6", "Tri_6"], "tetra10": ["Tetrahedron_10", "Tet_10"], "wedge": ["Wedge"], "wedge15": ["Wedge_15"], "wedge18": ["Wedge_18"], "hexahedron": ["Hexahedron"], "hexahedron20": ["Hexahedron_20", "Hex_20"], "hexahedron24": ["Hexahedron_24", "Hex_24"], "hexahedron27": ["Hexahedron_27", "Hex_27"], "hexahedron64": ["Hexahedron_64", "Hex_64"], "hexahedron125": ["Hexahedron_125", "Hex_125"], "hexahedron216": ["Hexahedron_216", "Hex_216"], "hexahedron343": ["Hexahedron_343", "Hex_343"], "hexahedron512": ["Hexahedron_512", "Hex_512"], "hexahedron729": ["Hexahedron_729", "Hex_729"], "hexahedron1000": ["Hexahedron_1000", "Hex_100"], "hexahedron1331": ["Hexahedron_1331", "Hex_1331"], } xdmf_to_meshio_type = {v: k for k, vals in meshio_to_xdmf_type.items() for v in vals} # Check out # # for the list of indices. xdmf_idx_to_meshio_type = { 0x1: "vertex", 0x2: "line", 0x4: "triangle", 0x5: "quad", 0x6: "tetra", 0x7: "pyramid", 0x8: "wedge", 0x9: "hexahedron", 0x22: "line3", 0x23: "quad9", 0x24: "triangle6", 0x25: "quad8", 0x26: "tetra10", 0x27: "pyramid13", 0x28: "wedge15", 0x29: "wedge18", 0x30: "hexahedron20", 0x31: "hexahedron24", 0x32: "hexahedron27", 0x33: "hexahedron64", 0x34: "hexahedron125", 0x35: "hexahedron216", 0x36: "hexahedron343", 0x37: "hexahedron512", 0x38: "hexahedron729", 0x39: "hexahedron1000", 0x40: "hexahedron1331", # 0x41: 'hexahedron_spectral_64', # 0x42: 'hexahedron_spectral_125', # 0x43: 'hexahedron_spectral_216', # 0x44: 'hexahedron_spectral_343', # 0x45: 'hexahedron_spectral_512', # 0x46: 'hexahedron_spectral_729', # 0x47: 'hexahedron_spectral_1000', # 0x48: 'hexahedron_spectral_1331', } meshio_type_to_xdmf_index = {v: k for k, v in xdmf_idx_to_meshio_type.items()} def translate_mixed_cells(data): # Translate it into the cells dictionary. # `data` is a one-dimensional vector with # (cell_type1, p0, p1, ... ,pk, cell_type2, p10, p11, ..., p1k, ... # https://xdmf.org/index.php/XDMF_Model_and_Format#Arbitrary # https://gitlab.kitware.com/xdmf/xdmf/blob/master/XdmfTopologyType.hpp#L394 xdmf_idx_to_num_nodes = { 1: 1, # vertex 2: 2, # line 4: 3, # triangle 5: 4, # quad 6: 4, # tet 7: 5, # pyramid 8: 6, # wedge 9: 8, # hex 11: 6, # triangle6 } # collect types and offsets types = [] offsets = [] r = 0 while r < len(data): xdmf_type = data[r] types.append(xdmf_type) offsets.append(r) if xdmf_type == 2: # line if data[r + 1] != 2: # polyline raise ReadError("XDMF reader: Only supports 2-point lines for now") r += 1 r += 1 r += xdmf_idx_to_num_nodes[xdmf_type] types = np.array(types) offsets = np.array(offsets) b = np.concatenate([[0], np.where(types[:-1] != types[1:])[0] + 1, [len(types)]]) cells = [] for start, end in zip(b[:-1], b[1:]): meshio_type = xdmf_idx_to_meshio_type[types[start]] n = xdmf_idx_to_num_nodes[types[start]] point_offsets = offsets[start:end] + (2 if types[start] == 2 else 1) indices = np.array([np.arange(n) + o for o in point_offsets]) cells.append(CellBlock(meshio_type, data[indices])) return cells def attribute_type(data): # if len(data.shape) == 1 or (len(data.shape) == 2 and data.shape[1] == 1): return "Scalar" elif len(data.shape) == 2 and data.shape[1] in [2, 3]: return "Vector" elif (len(data.shape) == 2 and data.shape[1] == 9) or ( len(data.shape) == 3 and data.shape[1] == 3 and data.shape[2] == 3 ): return "Tensor" elif len(data.shape) == 2 and data.shape[1] == 6: return "Tensor6" if len(data.shape) != 3: raise ReadError() return "Matrix" src/meshio/xdmf/main.py000066400000000000000000000452511456244072500154050ustar00rootroot00000000000000""" I/O for XDMF. https://xdmf.org/index.php/XDMF_Model_and_Format """ import os import pathlib from io import BytesIO from xml.etree import ElementTree as ET import numpy as np from .._common import cell_data_from_raw, raw_from_cell_data, write_xml from .._exceptions import ReadError, WriteError from .._helpers import register_format from .._mesh import CellBlock, Mesh from .common import ( attribute_type, dtype_to_format_string, meshio_to_xdmf_type, meshio_type_to_xdmf_index, numpy_to_xdmf_dtype, translate_mixed_cells, xdmf_to_meshio_type, xdmf_to_numpy_type, ) def read(filename): return XdmfReader(filename).read() class XdmfReader: def __init__(self, filename): self.filename = filename def read(self): parser = ET.XMLParser() tree = ET.parse(self.filename, parser) root = tree.getroot() if root.tag != "Xdmf": raise ReadError() version = root.attrib["Version"] if version.split(".")[0] == "2": return self.read_xdmf2(root) if version.split(".")[0] != "3": raise ReadError(f"Unknown XDMF version {version}.") return self.read_xdmf3(root) def _read_data_item(self, data_item, root=None): import h5py if "Reference" in data_item.attrib: reference = data_item.attrib["Reference"] xpath = (data_item.text if reference == "XML" else reference).strip() if xpath.startswith("/"): return self._read_data_item( root.find(".//" + "/".join(xpath.split("/")[2:])), root ) raise ValueError(f"Can't read XPath {xpath}.") dims = [int(d) for d in data_item.get("Dimensions").split()] # Actually, `NumberType` is XDMF2 and `DataType` XDMF3, but many files # out there use both keys interchangeably. if "DataType" in data_item.attrib and "NumberType" in data_item.attrib: raise ReadError() elif "DataType" in data_item.attrib: data_type = data_item.attrib["DataType"] elif "NumberType" in data_item.attrib: data_type = data_item.attrib["NumberType"] else: # Default, see # data_type = "Float" precision = data_item.get("Precision", default="4") fmt = data_item.attrib["Format"] if fmt == "XML": dtype = xdmf_to_numpy_type[(data_type, precision)] if data_item.text.strip() == "": # https://github.com/numpy/numpy/issues/18435 data = np.empty((0,), dtype=dtype) else: data = np.fromstring(data_item.text, dtype=dtype, sep=" ") return data.reshape(dims) elif fmt == "Binary": return np.fromfile( data_item.text.strip(), dtype=xdmf_to_numpy_type[(data_type, precision)] ).reshape(dims) if fmt != "HDF": raise ReadError(f"Unknown XDMF Format '{fmt}'.") info = data_item.text.strip() filename, h5path = info.split(":") # The HDF5 file path is given with respect to the XDMF (XML) file. dirname = pathlib.Path(self.filename).resolve().parent full_hdf5_path = dirname / filename f = h5py.File(full_hdf5_path, "r") # Some files don't contain the leading slash /. if h5path[0] == "/": h5path = h5path[1:] for key in h5path.split("/"): f = f[key] # `[()]` gives a np.ndarray return f[()] def read_information(self, c_data): field_data = {} root = ET.fromstring(c_data) for child in root: str_tag = child.attrib["key"] dim = int(child.attrib["dim"]) if child.text is None: raise ReadError() num_tag = int(child.text) field_data[str_tag] = np.array([num_tag, dim]) return field_data def read_xdmf2(self, root): # noqa: C901 domains = list(root) if len(domains) != 1: raise ReadError() domain = domains[0] if domain.tag != "Domain": raise ReadError() grids = list(domain) if len(grids) != 1: raise ReadError("XDMF reader: Only supports one grid right now.") grid = grids[0] if grid.tag != "Grid": raise ReadError() if "GridType" in grid.attrib and grid.attrib["GridType"] != "Uniform": raise ReadError() points = None cells = [] point_data = {} cell_data_raw = {} field_data = {} for c in grid: if c.tag == "Topology": data_items = list(c) if len(data_items) != 1: message = ( "Need exactly 1 data item in , " f"found {len(data_items)}." ) if len(data_items) == 0: message += ( "\nStructured meshes are not supported, see " "." ) raise ReadError(message) topology_type = c.attrib["TopologyType"] if topology_type == "Mixed": cells = translate_mixed_cells( np.fromstring( data_items[0].text, int, int(data_items[0].get("Dimensions")), " ", ) ) else: data = self._read_data_item(data_items[0]) cells.append(CellBlock(xdmf_to_meshio_type[topology_type], data)) elif c.tag == "Geometry": if "GeometryType" in c.attrib: geo_type = c.attrib["GeometryType"] if geo_type != "XYZ": raise ReadError(f'Expected GeometryType "XYZ", not {geo_type}.') data_items = list(c) if len(data_items) != 1: raise ReadError() points = self._read_data_item(data_items[0]) elif c.tag == "Information": c_data = c.text if not c_data: raise ReadError() field_data = self.read_information(c_data) elif c.tag == "Attribute": # assert c.attrib['Active'] == '1' # assert c.attrib['AttributeType'] == 'None' data_items = list(c) if len(data_items) != 1: raise ReadError() data = self._read_data_item(data_items[0]) name = c.attrib["Name"] if c.attrib["Center"] == "Node": point_data[name] = data elif c.attrib["Center"] == "Cell": cell_data_raw[name] = data else: # TODO field data? if c.attrib["Center"] != "Grid": raise ReadError() else: raise ReadError(f"Unknown section '{c.tag}'.") cell_data = cell_data_from_raw(cells, cell_data_raw) return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data, ) def read_xdmf3(self, root): # noqa: C901 domains = list(root) if len(domains) != 1: raise ReadError() domain = domains[0] if domain.tag != "Domain": raise ReadError() grids = list(domain) if len(grids) != 1: raise ReadError("XDMF reader: Only supports one grid right now.") grid = grids[0] if grid.tag != "Grid": raise ReadError() points = None cells = [] point_data = {} cell_data_raw = {} field_data = {} for c in grid: if c.tag == "Topology": data_items = list(c) if len(data_items) != 1: raise ReadError() data_item = data_items[0] data = self._read_data_item(data_item) # The XDMF2 key is `TopologyType`, just `Type` for XDMF3. Allow either # one. if "Type" in c.attrib and "TopologyType" in c.attrib: raise ReadError() elif "Type" in c.attrib: cell_type = c.attrib["Type"] else: cell_type = c.attrib["TopologyType"] if cell_type == "Mixed": cells = translate_mixed_cells(data) else: cells.append(CellBlock(xdmf_to_meshio_type[cell_type], data)) elif c.tag == "Geometry": if "Type" in c.attrib and "GeometryType" in c.attrib: raise ReadError() elif "Type" in c.attrib: geometry_type = c.attrib["Type"] else: geometry_type = c.attrib["GeometryType"] if geometry_type not in ["XY", "XYZ"]: raise ReadError(f'Illegal geometry type "{geometry_type}".') data_items = list(c) if len(data_items) != 1: raise ReadError() data_item = data_items[0] points = self._read_data_item(data_item) elif c.tag == "Information": c_data = c.text if not c_data: raise ReadError() field_data = self.read_information(c_data) elif c.tag == "Attribute": # Don't be too strict here: FEniCS, for example, calls this # 'AttributeType'. # assert c.attrib['Type'] == 'None' data_items = list(c) if len(data_items) != 1: raise ReadError() data_item = data_items[0] data = self._read_data_item(data_item) if c.attrib["Center"] not in ["Node", "Cell"]: raise ReadError(f"Unknown center '{c.attrib['Center']}'.") name = c.attrib["Name"] if c.attrib["Center"] == "Node": point_data[name] = data else: cell_data_raw[name] = data else: raise ReadError(f"Unknown section '{c.tag}'.") cell_data = cell_data_from_raw(cells, cell_data_raw) return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data, ) class XdmfWriter: def __init__( self, filename, mesh, data_format="HDF", compression="gzip", compression_opts=4 ): import h5py if data_format not in ["XML", "Binary", "HDF"]: raise WriteError( "Unknown XDMF data format " f"'{data_format}' (use 'XML', 'Binary', or 'HDF'.)" ) self.filename = pathlib.Path(filename) self.data_format = data_format self.data_counter = 0 self.compression = compression self.compression_opts = None if compression is None else compression_opts if data_format == "HDF": self.h5_filename = self.filename.with_suffix(".h5") self.h5_file = h5py.File(self.h5_filename, "w") xdmf_file = ET.Element("Xdmf", Version="3.0") domain = ET.SubElement(xdmf_file, "Domain") grid = ET.SubElement(domain, "Grid", Name="Grid") # information = ET.SubElement( # grid, "Information", Name="Information", Value=str(len(mesh.field_data)) # ) self.write_points(grid, mesh.points) # self.field_data(mesh.field_data, information) self.write_cells(mesh.cells, grid) self.write_point_data(mesh.point_data, grid) self.write_cell_data(mesh.cell_data, grid) ET.register_namespace("xi", "https://www.w3.org/2001/XInclude/") write_xml(filename, xdmf_file) def numpy_to_xml_string(self, data): if self.data_format == "XML": s = BytesIO() fmt = dtype_to_format_string[data.dtype.name] np.savetxt(s, data, fmt) return "\n" + s.getvalue().decode() elif self.data_format == "Binary": base = os.path.splitext(self.filename)[0] bin_filename = f"{base}{self.data_counter}.bin" self.data_counter += 1 # write binary data to file with open(bin_filename, "wb") as f: data.tofile(f) return bin_filename if self.data_format != "HDF": raise WriteError(f'Unknown data format "{self.data_format}"') name = f"data{self.data_counter}" self.data_counter += 1 self.h5_file.create_dataset( name, data=data, compression=self.compression, compression_opts=self.compression_opts, ) return os.path.basename(self.h5_filename) + ":/" + name def write_points(self, grid, points): if points.shape[1] > 3: raise WriteError("Can only write points up to dimension 3.") geometry_type = "XYZ"[: points.shape[1]] geo = ET.SubElement(grid, "Geometry", GeometryType=geometry_type) dt, prec = numpy_to_xdmf_dtype[points.dtype.name] dim = "{} {}".format(*points.shape) data_item = ET.SubElement( geo, "DataItem", DataType=dt, Dimensions=dim, Format=self.data_format, Precision=prec, ) data_item.text = self.numpy_to_xml_string(points) def write_cells(self, cells, grid): if len(cells) == 0: return if len(cells) == 1: meshio_type = cells[0].type num_cells = len(cells[0].data) xdmf_type = meshio_to_xdmf_type[meshio_type][0] topo = ET.SubElement( grid, "Topology", TopologyType=xdmf_type, NumberOfElements=str(num_cells), NodesPerElement=str(cells[0].data.shape[1]), ) dt, prec = numpy_to_xdmf_dtype[cells[0].data.dtype.name] dim = "{} {}".format(*cells[0].data.shape) data_item = ET.SubElement( topo, "DataItem", DataType=dt, Dimensions=dim, Format=self.data_format, Precision=prec, ) data_item.text = self.numpy_to_xml_string(cells[0].data) else: assert len(cells) > 1 total_num_cells = sum(c.data.shape[0] for c in cells) topo = ET.SubElement( grid, "Topology", TopologyType="Mixed", NumberOfElements=str(total_num_cells), ) total_num_cell_items = sum(np.prod(c.data.shape) for c in cells) num_vertices_and_lines = sum( c.data.shape[0] for c in cells if c.type in {"vertex", "line"} ) dim = str(total_num_cell_items + total_num_cells + num_vertices_and_lines) cd = np.concatenate( [ np.hstack( [ np.full( ( cell_block.data.shape[0], 2 if cell_block.type in {"vertex", "line"} else 1, ), meshio_type_to_xdmf_index[cell_block.type], ), cell_block.data, ] ).flatten() for cell_block in cells ] ) dt, prec = numpy_to_xdmf_dtype[cd.dtype.name] data_item = ET.SubElement( topo, "DataItem", DataType=dt, Dimensions=dim, Format=self.data_format, Precision=prec, ) data_item.text = self.numpy_to_xml_string(cd) def write_point_data(self, point_data, grid): for name, data in point_data.items(): att = ET.SubElement( grid, "Attribute", Name=name, AttributeType=attribute_type(data), Center="Node", ) dt, prec = numpy_to_xdmf_dtype[data.dtype.name] dim = " ".join([str(s) for s in data.shape]) data_item = ET.SubElement( att, "DataItem", DataType=dt, Dimensions=dim, Format=self.data_format, Precision=prec, ) data_item.text = self.numpy_to_xml_string(data) def write_cell_data(self, cell_data, grid): raw = raw_from_cell_data(cell_data) for name, data in raw.items(): att = ET.SubElement( grid, "Attribute", Name=name, AttributeType=attribute_type(data), Center="Cell", ) dt, prec = numpy_to_xdmf_dtype[data.dtype.name] dim = " ".join([str(s) for s in data.shape]) data_item = ET.SubElement( att, "DataItem", DataType=dt, Dimensions=dim, Format=self.data_format, Precision=prec, ) data_item.text = self.numpy_to_xml_string(data) # The original idea was to implement field data as XML CDATA. Unfortunately, in # Python's XML, CDATA handled poorly. There are workarounds, e.g., # , but those mess around with # ET._serialize_xml and lead to bugs elsewhere # . # def field_data(self, field_data, information): # info = ET.Element("main") # for name, data in field_data.items(): # data_item = ET.SubElement(info, "map", key=name, dim=str(data[1])) # data_item.text = str(data[0]) # information.text = ET.CDATA(ET.tostring(info)) # information.append(CDATA(ET.tostring(info).decode())) def write(*args, **kwargs): XdmfWriter(*args, **kwargs) # TODO register all xdmf except hdf outside this try block register_format( "xdmf", [".xdmf", ".xmf"], read, {"xdmf": write}, ) src/meshio/xdmf/time_series.py000066400000000000000000000402751456244072500167720ustar00rootroot00000000000000from __future__ import annotations import os import pathlib from io import BytesIO from xml.etree import ElementTree as ET import numpy as np from numpy.typing import ArrayLike from .._common import cell_data_from_raw, raw_from_cell_data, write_xml from .._exceptions import ReadError, WriteError from .._mesh import CellBlock from .common import ( attribute_type, dtype_to_format_string, meshio_to_xdmf_type, meshio_type_to_xdmf_index, numpy_to_xdmf_dtype, translate_mixed_cells, xdmf_to_meshio_type, xdmf_to_numpy_type, ) class TimeSeriesReader: def __init__(self, filename): # noqa: C901 self.filename = pathlib.Path(filename) parser = ET.XMLParser() tree = ET.parse(self.filename, parser) root = tree.getroot() if root.tag != "Xdmf": raise ReadError() version = root.attrib["Version"] if version.split(".")[0] != "3": raise ReadError(f"Unknown XDMF version {version}.") domains = list(root) if len(domains) != 1: raise ReadError() self.domain = domains[0] if self.domain.tag != "Domain": raise ReadError() grids = list(self.domain) # find the collection grid collection_grid = None for g in grids: if g.get("GridType") == "Collection": collection_grid = g if collection_grid is None: raise ReadError("Couldn't find the mesh grid") if collection_grid.tag != "Grid": raise ReadError() if collection_grid.get("CollectionType") != "Temporal": raise ReadError() # get the collection at once self.collection = list(collection_grid) self.num_steps = len(self.collection) self.cells = None self.hdf5_files = {} # find the uniform grid self.mesh_grid = None for g in grids: if g.get("GridType") == "Uniform": self.mesh_grid = g # if not found, take the first uniform grid in the collection grid if self.mesh_grid is None: for g in self.collection: if g.get("GridType") == "Uniform": self.mesh_grid = g break if self.mesh_grid is None: raise ReadError("Couldn't find the mesh grid") if self.mesh_grid.tag != "Grid": raise ReadError() def __enter__(self): return self def __exit__(self, *_): # Those files are opened in _read_data_item() for f in self.hdf5_files.values(): f.close() def read_points_cells(self): points = None cells = [] assert self.mesh_grid is not None for c in self.mesh_grid: if c.tag == "Topology": data_items = list(c) if len(data_items) != 1: raise ReadError() data_item = data_items[0] data = self._read_data_item(data_item) # The XDMF2 key is `TopologyType`, just `Type` for XDMF3. # Allow both. if "Type" in c.attrib: if "TopologyType" in c.attrib: raise ReadError("Both 'Type' and 'TopologyType' keys present") cell_type = c.attrib["Type"] else: cell_type = c.attrib["TopologyType"] if cell_type == "Mixed": cells = translate_mixed_cells(data) else: cells.append(CellBlock(xdmf_to_meshio_type[cell_type], data)) elif c.tag == "Geometry": if "GeometryType" in c.attrib: geo_type = c.attrib["GeometryType"] if geo_type not in ["XY", "XYZ"]: raise ReadError(f"Unknown geometry_type '{geo_type}'") data_items = list(c) if len(data_items) != 1: raise ReadError() data_item = data_items[0] points = self._read_data_item(data_item) self.cells = cells return points, cells def read_data(self, k: int): point_data = {} cell_data_raw = {} t = None for c in list(self.collection[k]): if c.tag == "Time": t = float(c.attrib["Value"]) elif c.tag == "Attribute": name = c.get("Name") if len(list(c)) != 1: raise ReadError() data_item = list(c)[0] data = self._read_data_item(data_item) if c.get("Center") == "Node": point_data[name] = data else: if c.get("Center") != "Cell": raise ReadError() cell_data_raw[name] = data else: # skip the xi:included mesh continue if self.cells is None: raise ReadError() cell_data = cell_data_from_raw(self.cells, cell_data_raw) if t is None: raise ReadError() return t, point_data, cell_data def _read_data_item(self, data_item): dims = [int(d) for d in data_item.get("Dimensions").split()] # Actually, `NumberType` is XDMF2 and `DataType` XDMF3, but many files out there # use both keys interchangeably. if data_item.get("DataType"): if data_item.get("NumberType"): raise ReadError() data_type = data_item.get("DataType") elif data_item.get("NumberType"): if data_item.get("DataType"): raise ReadError() data_type = data_item.get("NumberType") else: # Default, see # data_type = "Float" try: precision = data_item.attrib["Precision"] except KeyError: precision = "4" data_format = data_item.attrib["Format"] if data_format == "XML": return np.fromstring( data_item.text, dtype=xdmf_to_numpy_type[(data_type, precision)], sep=" ", ).reshape(dims) elif data_format == "Binary": return np.fromfile( data_item.text.strip(), dtype=xdmf_to_numpy_type[(data_type, precision)] ).reshape(dims) if data_format != "HDF": raise ReadError(f"Unknown XDMF Format '{data_format}'.") info = data_item.text.strip() filename, h5path = info.split(":") # The HDF5 file path is given with respect to the XDMF (XML) file. dirpath = self.filename.resolve().parent full_hdf5_path = dirpath / filename if full_hdf5_path in self.hdf5_files: f = self.hdf5_files[full_hdf5_path] else: import h5py f = h5py.File(full_hdf5_path, "r") self.hdf5_files[full_hdf5_path] = f if h5path[0] != "/": raise ReadError() for key in h5path[1:].split("/"): f = f[key] # `[()]` gives a np.ndarray return f[()] class TimeSeriesWriter: def __init__(self, filename, data_format: str = "HDF") -> None: if data_format not in ["XML", "Binary", "HDF"]: raise WriteError( "Unknown XDMF data format " f"'{data_format}' (use 'XML', 'Binary', or 'HDF'.)" ) self.filename = pathlib.Path(filename) self.data_format = data_format self.data_counter = 0 self.xdmf_file = ET.Element("Xdmf", Version="3.0") self.domain = ET.SubElement(self.xdmf_file, "Domain") self.collection = ET.SubElement( self.domain, "Grid", Name="TimeSeries_meshio", GridType="Collection", CollectionType="Temporal", ) ET.register_namespace("xi", "https://www.w3.org/2001/XInclude/") self.has_mesh = False self.mesh_name = "mesh" def __enter__(self): if self.data_format == "HDF": import h5py self.h5_filename = self.filename.stem + ".h5" self.h5_file = h5py.File(self.h5_filename, "w") return self def __exit__(self, *_): write_xml(self.filename, self.xdmf_file) if self.data_format == "HDF": self.h5_file.close() def write_points_cells( self, points: ArrayLike, cells: dict[str, ArrayLike] | list[tuple[str, ArrayLike] | CellBlock], ) -> None: # # # maxwell.h5:/Mesh/0/mesh/topology # # # maxwell.h5:/Mesh/0/mesh/geometry # # grid = ET.SubElement( self.domain, "Grid", Name=self.mesh_name, GridType="Uniform" ) self.points(grid, np.asarray(points)) self.cells(cells, grid) self.has_mesh = True def write_data(self, t, point_data=None, cell_data=None): cell_data = {} if cell_data is None else cell_data # # # grid = ET.SubElement(self.collection, "Grid") if not self.has_mesh: raise WriteError() ptr = f'xpointer(//Grid[@Name="{self.mesh_name}"]/*[self::Topology or self::Geometry])' ET.SubElement(grid, "{http://www.w3.org/2003/XInclude}include", xpointer=ptr) ET.SubElement(grid, "Time", Value=str(t)) if point_data: self.point_data(point_data, grid) # permit old dict structure, convert it to list of tuples for name, entry in cell_data.items(): if isinstance(entry, dict): cell_data[name] = np.array(list(entry.values())) if cell_data: self.cell_data(cell_data, grid) def numpy_to_xml_string(self, data): if self.data_format == "XML": s = BytesIO() fmt = dtype_to_format_string[data.dtype.name] np.savetxt(s, data.flatten(), fmt) return s.getvalue().decode() elif self.data_format == "Binary": bin_filename = f"{self.filename.stem}{self.data_counter}.bin" self.data_counter += 1 # write binary data to file with open(bin_filename, "wb") as f: data.tofile(f) return bin_filename if self.data_format != "HDF": raise WriteError() name = f"data{self.data_counter}" self.data_counter += 1 self.h5_file.create_dataset(name, data=data) return os.path.basename(self.h5_filename) + ":/" + name def points(self, grid, points): if points.shape[1] == 2: geometry_type = "XY" else: if points.shape[1] != 3: raise WriteError("Need 3D points.") geometry_type = "XYZ" geo = ET.SubElement(grid, "Geometry", GeometryType=geometry_type) dt, prec = numpy_to_xdmf_dtype[points.dtype.name] dim = "{} {}".format(*points.shape) data_item = ET.SubElement( geo, "DataItem", DataType=dt, Dimensions=dim, Format=self.data_format, Precision=prec, ) data_item.text = self.numpy_to_xml_string(points) def cells( self, cells: dict[str, ArrayLike] | list[tuple[str, ArrayLike] | CellBlock], grid: ET.Element, ) -> None: if isinstance(cells, dict): # convert dict to list of tuples cells = list(cells.items()) # conver to cell_blocks cell_blocks = [] for cell_block in cells: if isinstance(cell_block, tuple): cell_type, data = cell_block cell_block = CellBlock(cell_type, np.asarray(data)) cell_blocks.append(cell_block) if len(cell_blocks) == 1: meshio_type = cell_blocks[0].type num_cells = len(cell_blocks[0].data) xdmf_type = meshio_to_xdmf_type[meshio_type][0] topo = ET.SubElement( grid, "Topology", TopologyType=xdmf_type, NumberOfElements=str(num_cells), ) dt, prec = numpy_to_xdmf_dtype[cell_blocks[0].data.dtype.name] data_item = ET.SubElement( topo, "DataItem", DataType=dt, Dimensions="{} {}".format(*cell_blocks[0].data.shape), Format=self.data_format, Precision=prec, ) data_item.text = self.numpy_to_xml_string(cell_blocks[0].data) elif len(cell_blocks) > 1: total_num_cells = sum(len(c.data) for c in cell_blocks) topo = ET.SubElement( grid, "Topology", TopologyType="Mixed", NumberOfElements=str(total_num_cells), ) total_num_cell_items = sum(np.prod(c.data.shape) for c in cell_blocks) dim = total_num_cell_items + total_num_cells # Lines translate to Polylines, and one needs to specify the exact # number of nodes. Hence, prepend 2. for c in cell_blocks: if c.type == "line": c.data[:] = np.insert(c.data, 0, 2, axis=1) dim += len(c.data) dim = str(dim) cd = np.concatenate( [ # prepend column with xdmf type index np.insert( c.data, 0, meshio_type_to_xdmf_index[c.type], axis=1 ).flatten() for c in cell_blocks ] ) dt, prec = numpy_to_xdmf_dtype[cd.dtype.name] data_item = ET.SubElement( topo, "DataItem", DataType=dt, Dimensions=dim, Format=self.data_format, Precision=prec, ) data_item.text = self.numpy_to_xml_string(cd) def point_data(self, point_data: dict[str, np.ndarray], grid: ET.Element): for name, data in point_data.items(): att = ET.SubElement( grid, "Attribute", Name=name, AttributeType=attribute_type(data), Center="Node", ) dt, prec = numpy_to_xdmf_dtype[data.dtype.name] dim = " ".join([str(s) for s in data.shape]) data_item = ET.SubElement( att, "DataItem", DataType=dt, Dimensions=dim, Format=self.data_format, Precision=prec, ) data_item.text = self.numpy_to_xml_string(data) def cell_data( self, cell_data: dict[str, list[np.ndarray]], grid: ET.Element ) -> None: raw = raw_from_cell_data(cell_data) for name, data in raw.items(): att = ET.SubElement( grid, "Attribute", Name=name, AttributeType=attribute_type(data), Center="Cell", ) dt, prec = numpy_to_xdmf_dtype[data.dtype.name] dim = " ".join([str(s) for s in data.shape]) data_item = ET.SubElement( att, "DataItem", DataType=dt, Dimensions=dim, Format=self.data_format, Precision=prec, ) data_item.text = self.numpy_to_xml_string(data) tests/000077500000000000000000000000001456244072500122315ustar00rootroot00000000000000tests/__init__.py000066400000000000000000000000001456244072500143300ustar00rootroot00000000000000tests/helpers.py000066400000000000000000000536111456244072500142530ustar00rootroot00000000000000from __future__ import annotations import copy import string import numpy as np import meshio # In general: # Use values with an infinite decimal representation to test precision. empty_mesh = meshio.Mesh(np.empty((0, 3)), []) line_mesh = meshio.Mesh( [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]], [("line", [[0, 1], [0, 2], [0, 3], [1, 2], [2, 3]])], ) tri_mesh_one_cell = meshio.Mesh( [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0]], [("triangle", [[0, 1, 2]])], ) tri_mesh_2d = meshio.Mesh( [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]], [("triangle", [[0, 1, 2], [0, 2, 3]])], ) tri_mesh_5 = meshio.Mesh( [ [0.0, 0.0], [1.0, 0.0], [2.0, 0.0], [3.0, 1.0], [2.0, 1.0], [1.0, 1.0], [0.0, 1.0], ], [("triangle", [[0, 1, 5], [0, 5, 6], [1, 2, 5], [2, 4, 5], [2, 3, 4]])], ) tri_mesh = meshio.Mesh( [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]], [("triangle", [[0, 1, 2], [0, 2, 3]])], ) line_tri_mesh = meshio.Mesh(line_mesh.points, line_mesh.cells + tri_mesh.cells) triangle6_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.5, 0.25, 0.0], [1.25, 0.5, 0.0], [0.25, 0.75, 0.0], [2.0, 1.0, 0.0], [1.5, 1.25, 0.0], [1.75, 0.25, 0.0], ], [("triangle6", [[0, 1, 2, 3, 4, 5], [1, 6, 2, 8, 7, 4]])], ) quad_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [2.0, 0.0, 0.0], [2.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], ], [("quad", [[0, 1, 4, 5], [1, 2, 3, 4]])], ) d = 0.1 quad8_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], [0.5, d, 0.0], [1 - d, 0.5, 0.0], [0.5, 1 - d, 0.0], [d, 0.5, 0.0], [2.0, 0.0, 0.0], [2.0, 1.0, 0.0], [1.5, -d, 0.0], [2 + d, 0.5, 0.0], [1.5, 1 + d, 0.0], ], [("quad8", [[0, 1, 2, 3, 4, 5, 6, 7], [1, 8, 9, 2, 10, 11, 12, 5]])], ) tri_quad_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [2.0, 0.0, 0.0], [3.0, 1.0, 0.0], [2.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], ], [ ("triangle", [[0, 1, 5], [0, 5, 6]]), ("quad", [[1, 2, 4, 5]]), ("triangle", [[2, 3, 4]]), ], ) # same as tri_quad_mesh with reversed cell type order quad_tri_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [2.0, 0.0, 0.0], [2.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], ], [ ("quad", [[1, 2, 3, 4]]), ("triangle", [[0, 1, 4], [0, 4, 5]]), ], ) tet_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], [0.5, 0.5, 0.5], ], [("tetra", [[0, 1, 2, 4], [0, 2, 3, 4]])], ) tet10_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.5, 0.5, 0.5], # [0.5, 0.0, 0.1], [1.0, 0.5, 0.1], [0.5, 0.5, 0.1], [0.25, 0.3, 0.25], [0.8, 0.25, 0.25], [0.7, 0.7, 0.3], ], [("tetra10", [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])], ) hex_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 1.0], [0.0, 1.0, 1.0], ], [("hexahedron", [[0, 1, 2, 3, 4, 5, 6, 7]])], ) wedge_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 1.0], ], [("wedge", [[0, 1, 2, 3, 4, 5]])], ) pyramid_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], [0.5, 0.5, 1.0], ], [("pyramid", [[0, 1, 2, 3, 4]])], ) hex20_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 1.0], [0.0, 1.0, 1.0], # [0.5, 0.0, 0.0], [1.0, 0.5, 0.0], [0.5, 1.0, 0.0], [0.0, 0.5, 0.0], # [0.0, 0.0, 0.5], [1.0, 0.0, 0.5], [1.0, 1.0, 0.5], [0.0, 1.0, 0.5], # [0.5, 0.0, 1.0], [1.0, 0.5, 1.0], [0.5, 1.0, 1.0], [0.0, 0.5, 1.0], ], [("hexahedron20", [np.arange(20)])], ) polygon_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], [1.5, 0.0, 0.0], [1.7, 0.5, 0.0], [1.5, 1.2, 0.0], [-0.1, 1.1, 0.0], [-0.5, 1.4, 0.0], [-0.7, 0.8, 0.0], [-0.3, -0.1, 0.0], ], [ ("triangle", [[0, 1, 2], [4, 5, 6]]), ("quad", [[0, 1, 2, 3]]), ("polygon", [[1, 4, 5, 6, 2]]), ("polygon", [[0, 3, 7, 8, 9, 10], [1, 3, 7, 8, 9, 10]]), ], ) polygon_mesh_one_cell = meshio.Mesh( [ [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [1.5, 0.0, 0.0], [1.7, 0.5, 0.0], [1.5, 1.2, 0.0], ], [ ("polygon", [[0, 2, 3, 4, 1]]), ], ) # Make sure that the polygon cell blocking works. # This mesh is identical with tri_quad_mesh. polygon2_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [2.0, 0.0, 0.0], [3.0, 1.0, 0.0], [2.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], ], [ ("polygon", [[0, 1, 5], [0, 5, 6]]), ("polygon", [[1, 2, 4, 5]]), ("polygon", [[2, 3, 4]]), ], ) polyhedron_mesh = meshio.Mesh( [ # Two layers of a unit square [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 1.0], [0.0, 1.0, 1.0], ], # Split the cube into tets and pyramids. [ ( "polyhedron4", [ [ [1, 2, 5], [1, 2, 7], [1, 5, 7], [2, 5, 7], ], [ [2, 5, 6], [2, 6, 7], [2, 5, 7], [5, 6, 7], ], ], ), ( "polyhedron5", [ [ # np.asarray on this causes a numpy warning # ``` # VisibleDeprecationWarning: Creating an ndarray from ragged nested # sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays # with different lengths or shapes) is deprecated. If you meant to # do this, you must specify 'dtype=object' when creating the # ndarray. # ``` # TODO come up with a better data structure for polyhedra [0, 1, 2, 3], # pyramid base is a rectangle [0, 1, 7], [1, 2, 7], [2, 3, 7], [3, 0, 7], ], [ [0, 1, 5], # pyramid base split in two triangles [0, 4, 5], [0, 1, 7], [1, 5, 7], [5, 4, 7], [0, 4, 7], ], ], ), ], ) # From : lagrange_high_order_mesh = meshio.Mesh( [ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [0.14285714924, 0.0, 0.0], [0.28571429849, 0.0, 0.0], [0.42857143283, 0.0, 0.0], [0.57142859697, 0.0, 0.0], [0.71428573132, 0.0, 0.0], [0.85714286566, 0.0, 0.0], [0.0, 0.14285714924, 0.0], [0.14285714924, 0.14285714924, 0.0], [0.28571428359, 0.14285714924, 0.0], [0.42857144773, 0.14285714924, 0.0], [0.57142858207, 0.14285714924, 0.0], [0.71428571641, 0.14285714924, 0.0], [0.85714285076, 0.14285714924, 0.0], [0.0, 0.28571429849, 0.0], [0.14285713434, 0.28571429849, 0.0], [0.28571429849, 0.28571429849, 0.0], [0.42857143283, 0.28571429849, 0.0], [0.57142856717, 0.28571429849, 0.0], [0.71428570151, 0.28571429849, 0.0], [0.0, 0.42857143283, 0.0], [0.14285716414, 0.42857143283, 0.0], [0.28571429849, 0.42857143283, 0.0], [0.42857143283, 0.42857143283, 0.0], [0.57142856717, 0.42857143283, 0.0], [0.0, 0.57142859697, 0.0], [0.14285713434, 0.57142859697, 0.0], [0.28571426868, 0.57142859697, 0.0], [0.42857140303, 0.57142859697, 0.0], [0.0, 0.71428573132, 0.0], [0.14285713434, 0.71428573132, 0.0], [0.28571426868, 0.71428573132, 0.0], [0.0, 0.85714286566, 0.0], [0.14285713434, 0.85714286566, 0.0], [0.0, 0.0, 0.14285714924], [0.14285714179, 0.0, 0.14285714924], [0.28571429104, 0.0, 0.14285714924], [0.42857142538, 0.0, 0.14285714924], [0.57142855972, 0.0, 0.14285714924], [0.71428569406, 0.0, 0.14285714924], [0.8571428284, 0.0, 0.14285714924], [0.0, 0.14285714179, 0.14285714924], [0.14285714924, 0.14285714179, 0.14285714924], [0.28571428359, 0.14285714179, 0.14285714924], [0.42857141793, 0.14285714179, 0.14285714924], [0.57142855227, 0.14285714179, 0.14285714924], [0.71428568661, 0.14285714179, 0.14285714924], [0.0, 0.28571429104, 0.14285714924], [0.14285713434, 0.28571429104, 0.14285714924], [0.28571426868, 0.28571429104, 0.14285714924], [0.42857140303, 0.28571429104, 0.14285714924], [0.57142853737, 0.28571429104, 0.14285714924], [0.0, 0.42857142538, 0.14285714924], [0.14285713434, 0.42857142538, 0.14285714924], [0.28571426868, 0.42857142538, 0.14285714924], [0.42857140303, 0.42857142538, 0.14285714924], [0.0, 0.57142855972, 0.14285714924], [0.14285713434, 0.57142855972, 0.14285714924], [0.28571426868, 0.57142855972, 0.14285714924], [0.0, 0.71428569406, 0.14285714924], [0.14285713434, 0.71428569406, 0.14285714924], [0.0, 0.8571428284, 0.14285714924], [0.0, 0.0, 0.28571429849], [0.14285714924, 0.0, 0.28571429849], [0.28571428359, 0.0, 0.28571429849], [0.42857144773, 0.0, 0.28571429849], [0.57142858207, 0.0, 0.28571429849], [0.71428571641, 0.0, 0.28571429849], [0.0, 0.14285714924, 0.28571429849], [0.14285713434, 0.14285714924, 0.28571429849], [0.28571429849, 0.14285714924, 0.28571429849], [0.42857143283, 0.14285714924, 0.28571429849], [0.57142856717, 0.14285714924, 0.28571429849], [0.0, 0.28571428359, 0.28571429849], [0.14285716414, 0.28571428359, 0.28571429849], [0.28571429849, 0.28571428359, 0.28571429849], [0.42857143283, 0.28571428359, 0.28571429849], [0.0, 0.42857144773, 0.28571429849], [0.14285713434, 0.42857144773, 0.28571429849], [0.28571426868, 0.42857144773, 0.28571429849], [0.0, 0.57142858207, 0.28571429849], [0.14285713434, 0.57142858207, 0.28571429849], [0.0, 0.71428571641, 0.28571429849], [0.0, 0.0, 0.42857143283], [0.14285714924, 0.0, 0.42857143283], [0.28571428359, 0.0, 0.42857143283], [0.42857141793, 0.0, 0.42857143283], [0.57142855227, 0.0, 0.42857143283], [0.0, 0.14285714924, 0.42857143283], [0.14285713434, 0.14285714924, 0.42857143283], [0.28571426868, 0.14285714924, 0.42857143283], [0.42857140303, 0.14285714924, 0.42857143283], [0.0, 0.28571428359, 0.42857143283], [0.14285713434, 0.28571428359, 0.42857143283], [0.28571426868, 0.28571428359, 0.42857143283], [0.0, 0.42857141793, 0.42857143283], [0.14285713434, 0.42857141793, 0.42857143283], [0.0, 0.57142855227, 0.42857143283], [0.0, 0.0, 0.57142859697], [0.14285713434, 0.0, 0.57142859697], [0.28571429849, 0.0, 0.57142859697], [0.42857143283, 0.0, 0.57142859697], [0.0, 0.14285713434, 0.57142859697], [0.14285716414, 0.14285713434, 0.57142859697], [0.28571429849, 0.14285713434, 0.57142859697], [0.0, 0.28571429849, 0.57142859697], [0.14285713434, 0.28571429849, 0.57142859697], [0.0, 0.42857143283, 0.57142859697], [0.0, 0.0, 0.71428573132], [0.14285713434, 0.0, 0.71428573132], [0.28571426868, 0.0, 0.71428573132], [0.0, 0.14285713434, 0.71428573132], [0.14285713434, 0.14285713434, 0.71428573132], [0.0, 0.28571426868, 0.71428573132], [0.0, 0.0, 0.85714286566], [0.14285716414, 0.0, 0.85714286566], [0.0, 0.14285716414, 0.85714286566], ], [ ( "VTK_LAGRANGE_TETRAHEDRON", [ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 22, 27, 31, 34, 36, 35, 32, 28, 23, 17, 10, 37, 65, 86, 101, 111, 117, 43, 70, 90, 104, 113, 118, 64, 85, 100, 110, 116, 119, 38, 42, 112, 39, 40, 41, 69, 89, 103, 102, 87, 66, 67, 68, 88, 63, 115, 49, 84, 99, 109, 107, 94, 75, 54, 58, 61, 82, 97, 79, 44, 114, 62, 71, 91, 105, 108, 98, 83, 59, 55, 50, 76, 95, 80, 11, 33, 15, 18, 24, 29, 30, 26, 21, 14, 13, 12, 19, 25, 20, 45, 48, 60, 106, 46, 47, 53, 57, 56, 51, 72, 92, 74, 93, 81, 96, 73, 78, 77, 52, ] ], ) ], ) def add_point_data(mesh, dim, num_tags=2, seed=0, dtype=float): rng = np.random.default_rng(seed) mesh2 = copy.deepcopy(mesh) shape = (len(mesh.points),) if dim == 1 else (len(mesh.points), dim) data = [(100 * rng.random(shape)).astype(dtype) for _ in range(num_tags)] mesh2.point_data = {string.ascii_lowercase[k]: d for k, d in enumerate(data)} return mesh2 def add_cell_data(mesh, specs: list[tuple[str, tuple[int, ...], type]]): mesh2 = copy.deepcopy(mesh) rng = np.random.default_rng(0) mesh2.cell_data = { name: [ (100 * rng.random((len(cellblock),) + shape)).astype(dtype) for cellblock in mesh.cells ] for name, shape, dtype in specs } # Keep cell-data from the original mesh. This is needed to preserve # face-cell relations for polyhedral meshes. for key, val in mesh.cell_data.items(): mesh2.cell_data[key] = val return mesh2 def add_field_data(mesh, value, dtype): mesh2 = copy.deepcopy(mesh) mesh2.field_data = {"a": np.array(value, dtype=dtype)} return mesh2 def add_point_sets(mesh): mesh2 = copy.deepcopy(mesh) n = len(mesh.points) mesh2.point_sets = { "fixed": np.arange(0, n // 2), "loose": np.arange(n // 2, n), } return mesh2 def add_cell_sets(mesh): mesh2 = copy.deepcopy(mesh) assert len(mesh.cells) == 1 n = len(mesh.cells[0]) mesh2.cell_sets = { "grain0": [np.arange(0, n // 2)], "grain1": [np.arange(n // 2, n)], } return mesh2 def write_read(tmp_path, writer, reader, input_mesh, atol, extension=".dat"): """Write and read a file, and make sure the data is the same as before.""" in_mesh = copy.deepcopy(input_mesh) p = tmp_path / ("test" + extension) print(input_mesh) writer(p, input_mesh) mesh = reader(p) # Make sure the output is writeable assert mesh.points.flags["WRITEABLE"] for cells in input_mesh.cells: if isinstance(cells.data, np.ndarray): assert cells.data.flags["WRITEABLE"] else: # This is assumed to be a polyhedron for cell in cells.data: for face in cell: assert face.flags["WRITEABLE"] # assert that the input mesh hasn't changed at all assert in_mesh.points.dtype == input_mesh.points.dtype assert np.allclose(in_mesh.points, input_mesh.points, atol=atol, rtol=0.0) for c0, c1 in zip(in_mesh.cells, input_mesh.cells): if c0.type.startswith("polyhedron"): continue assert c0.type == c1.type assert c0.data.shape == c1.data.shape, f"{c0.data.shape} != {c1.data.shape}" assert c0.data.dtype == c1.data.dtype, f"{c0.data.dtype} != {c1.data.dtype}" assert np.all(c0.data == c1.data) # Numpy's array_equal is too strict here, cf. # . # Use allclose. if in_mesh.points.shape[0] == 0: assert mesh.points.shape[0] == 0 else: n = in_mesh.points.shape[1] assert np.allclose(in_mesh.points, mesh.points[:, :n], atol=atol, rtol=0.0) # To avoid errors from sorted (below), specify the key as first cell type then index # of the first point of the first cell. This may still lead to comparison of what # should be different blocks, but chances seem low. def cell_sorter(cell): if cell.type.startswith("polyhedron"): # Polyhedra blocks should be well enough distinguished by their type return cell.type else: return (cell.type, cell.data[0, 0]) # to make sure we are testing the same type of cells we sort the list for cells0, cells1 in zip( sorted(input_mesh.cells, key=cell_sorter), sorted(mesh.cells, key=cell_sorter) ): assert cells0.type == cells1.type, f"{cells0.type} != {cells1.type}" if cells0.type.startswith("polyhedron"): # Special treatment of polyhedron cells # Data is a list (one item per cell) of numpy arrays for c_in, c_out in zip(cells0.data, cells1.data): for face_in, face_out in zip(c_in, c_out): assert np.allclose(face_in, face_out, atol=atol, rtol=0.0) else: print("a", cells0.data) print("b", cells1.data) assert np.array_equal(cells0.data, cells1.data) for key in input_mesh.point_data.keys(): assert np.allclose( input_mesh.point_data[key], mesh.point_data[key], atol=atol, rtol=0.0 ) print(input_mesh.cell_data) print() print(mesh.cell_data) for name, cell_type_data in input_mesh.cell_data.items(): for d0, d1 in zip(cell_type_data, mesh.cell_data[name]): # assert d0.dtype == d1.dtype, (d0.dtype, d1.dtype) assert np.allclose(d0, d1, atol=atol, rtol=0.0) for name, data in input_mesh.field_data.items(): if isinstance(data, list): assert data == mesh.field_data[name] else: assert np.allclose(data, mesh.field_data[name], atol=atol, rtol=0.0) # Test of cell sets (assumed to be a list of numpy arrays), for name, data in input_mesh.cell_sets.items(): # Skip the test if the key is not in the read cell set if name not in mesh.cell_sets.keys(): continue data2 = mesh.cell_sets[name] for var1, var2 in zip(data, data2): assert np.allclose(var1, var2, atol=atol, rtol=0.0) def generic_io(filepath): meshio.write_points_cells(filepath, tri_mesh.points, tri_mesh.cells) out_mesh = meshio.read(filepath) assert (abs(out_mesh.points - tri_mesh.points) < 1.0e-15).all() for c0, c1 in zip(tri_mesh.cells, out_mesh.cells): assert c0.type == c1.type assert (c0.data == c1.data).all() tests/legacy_reader.py000066400000000000000000000152351456244072500153770ustar00rootroot00000000000000import numpy as np from meshio import Mesh from meshio.vtk_io import vtk_to_meshio_type def read(filetype, filename): import vtk from vtk.util import numpy as numpy_support def _read_data(data): """Extract numpy arrays from a VTK data set.""" # Go through all arrays, fetch data. out = {} for k in range(data.GetNumberOfArrays()): array = data.GetArray(k) if array: array_name = array.GetName() out[array_name] = np.copy(vtk.util.numpy_support.vtk_to_numpy(array)) return out def _read_cells(vtk_mesh): data = np.copy( vtk.util.numpy_support.vtk_to_numpy(vtk_mesh.GetCells().GetData()) ) offsets = np.copy( vtk.util.numpy_support.vtk_to_numpy(vtk_mesh.GetCellLocationsArray()) ) types = np.copy( vtk.util.numpy_support.vtk_to_numpy(vtk_mesh.GetCellTypesArray()) ) # `data` is a one-dimensional vector with # (num_points0, p0, p1, ... ,pk, numpoints1, p10, p11, ..., p1k, ... # Translate it into the cells dictionary. cells = {} for vtk_type, meshio_type in vtk_to_meshio_type.items(): # Get all offsets for vtk_type os = offsets[np.argwhere(types == vtk_type).transpose()[0]] num_cells = len(os) if num_cells > 0: if meshio_type == "polygon": for idx_cell in range(num_cells): num_pts = data[os[idx_cell]] cell = data[os[idx_cell] + 1 : os[idx_cell] + 1 + num_pts] key = meshio_type + str(num_pts) if key in cells: cells[key] = np.vstack([cells[key], cell]) else: cells[key] = cell else: num_pts = data[os[0]] # instantiate the array arr = np.empty((num_cells, num_pts), dtype=int) # store the num_pts entries after the offsets into the columns # of arr for k in range(num_pts): arr[:, k] = data[os + k + 1] cells[meshio_type] = arr return cells if filetype in ["vtk", "vtk-ascii", "vtk-binary"]: reader = vtk.vtkUnstructuredGridReader() reader.SetFileName(filename) reader.SetReadAllNormals(1) reader.SetReadAllScalars(1) reader.SetReadAllTensors(1) reader.SetReadAllVectors(1) reader.Update() vtk_mesh = reader.GetOutput() elif filetype in ["vtu", "vtu-ascii", "vtu-binary"]: reader = vtk.vtkXMLUnstructuredGridReader() reader.SetFileName(filename) reader.Update() vtk_mesh = reader.GetOutput() elif filetype in ["xdmf", "xdmf2"]: reader = vtk.vtkXdmfReader() reader.SetFileName(filename) reader.SetReadAllColorScalars(1) reader.SetReadAllFields(1) reader.SetReadAllNormals(1) reader.SetReadAllScalars(1) reader.SetReadAllTCoords(1) reader.SetReadAllTensors(1) reader.SetReadAllVectors(1) reader.Update() vtk_mesh = reader.GetOutputDataObject(0) elif filetype == "xdmf3": reader = vtk.vtkXdmf3Reader() reader.SetFileName(filename) reader.SetReadAllColorScalars(1) reader.SetReadAllFields(1) reader.SetReadAllNormals(1) reader.SetReadAllScalars(1) reader.SetReadAllTCoords(1) reader.SetReadAllTensors(1) reader.SetReadAllVectors(1) reader.Update() vtk_mesh = reader.GetOutputDataObject(0) else: assert filetype == "exodus", f"Unknown file type '{filename}'." reader = vtk.vtkExodusIIReader() reader.SetFileName(filename) vtk_mesh = _read_exodusii_mesh(reader) # Explicitly extract points, cells, point data, field data points = np.copy(numpy_support.vtk_to_numpy(vtk_mesh.GetPoints().GetData())) cells = _read_cells(vtk_mesh) point_data = _read_data(vtk_mesh.GetPointData()) field_data = _read_data(vtk_mesh.GetFieldData()) cell_data = _read_data(vtk_mesh.GetCellData()) # split cell_data by the cell type cd = {} index = 0 for cell_type in cells: num_cells = len(cells[cell_type]) cd[cell_type] = {} for name, array in cell_data.items(): cd[cell_type][name] = array[index : index + num_cells] index += num_cells cell_data = cd return Mesh( points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data ) def _read_exodusii_mesh(reader, timestep=None): """Uses a vtkExodusIIReader to return a vtkUnstructuredGrid.""" # Fetch metadata. reader.UpdateInformation() # Set time step to read. if timestep: reader.SetTimeStep(timestep) # Make sure the point data are read during Update(). for k in range(reader.GetNumberOfPointResultArrays()): arr_name = reader.GetPointResultArrayName(k) reader.SetPointResultArrayStatus(arr_name, 1) # Make sure the cell data are read during Update(). for k in range(reader.GetNumberOfElementResultArrays()): arr_name = reader.GetElementResultArrayName(k) reader.SetElementResultArrayStatus(arr_name, 1) # Make sure all field data is read. for k in range(reader.GetNumberOfGlobalResultArrays()): arr_name = reader.GetGlobalResultArrayName(k) reader.SetGlobalResultArrayStatus(arr_name, 1) # Read the file. reader.Update() out = reader.GetOutput() # Loop through the blocks and search for a vtkUnstructuredGrid. # In Exodus, different element types are stored different meshes, with # point information possibly duplicated. vtk_mesh = [] for i in range(out.GetNumberOfBlocks()): blk = out.GetBlock(i) for j in range(blk.GetNumberOfBlocks()): sub_block = blk.GetBlock(j) if sub_block is not None and sub_block.IsA("vtkUnstructuredGrid"): vtk_mesh.append(sub_block) assert vtk_mesh, "No 'vtkUnstructuredGrid' found!" assert len(vtk_mesh) == 1, "More than one 'vtkUnstructuredGrid' found!" # Cut off trailing '_' from array names. for k in range(vtk_mesh[0].GetPointData().GetNumberOfArrays()): array = vtk_mesh[0].GetPointData().GetArray(k) array_name = array.GetName() if array_name[-1] == "_": array.SetName(array_name[0:-1]) # time_values = reader.GetOutputInformation(0).Get( # vtkStreamingDemandDrivenPipeline.TIME_STEPS() # ) return vtk_mesh[0] # , time_values tests/legacy_writer.py000066400000000000000000000152441456244072500154510ustar00rootroot00000000000000import logging import numpy as np # https://vtk.org/doc/nightly/html/vtkCellType_8h_source.html vtk_to_meshio_type = { 0: "empty", 1: "vertex", # 2: 'poly_vertex', 3: "line", # 4: 'poly_line', 5: "triangle", # 6: 'triangle_strip', 7: "polygon", # 8: 'pixel', 9: "quad", 10: "tetra", # 11: 'voxel', 12: "hexahedron", 13: "wedge", 14: "pyramid", 15: "penta_prism", 16: "hexa_prism", 21: "line3", 22: "triangle6", 23: "quad8", 24: "tetra10", 25: "hexahedron20", 26: "wedge15", 27: "pyramid13", 28: "quad9", 29: "hexahedron27", 30: "quad6", 31: "wedge12", 32: "wedge18", 33: "hexahedron24", 34: "triangle7", 35: "line4", # # 60: VTK_HIGHER_ORDER_EDGE, # 61: VTK_HIGHER_ORDER_TRIANGLE, # 62: VTK_HIGHER_ORDER_QUAD, # 63: VTK_HIGHER_ORDER_POLYGON, # 64: VTK_HIGHER_ORDER_TETRAHEDRON, # 65: VTK_HIGHER_ORDER_WEDGE, # 66: VTK_HIGHER_ORDER_PYRAMID, # 67: VTK_HIGHER_ORDER_HEXAHEDRON, } def _get_writer(filetype, filename): import vtk if filetype in "vtk-ascii": logging.warning("VTK ASCII files are only meant for debugging.") writer = vtk.vtkUnstructuredGridWriter() writer.SetFileTypeToASCII() elif filetype == "vtk-binary": writer = vtk.vtkUnstructuredGridWriter() writer.SetFileTypeToBinary() elif filetype == "vtu-ascii": logging.warning("VTU ASCII files are only meant for debugging.") writer = vtk.vtkXMLUnstructuredGridWriter() writer.SetDataModeToAscii() elif filetype == "vtu-binary": writer = vtk.vtkXMLUnstructuredGridWriter() writer.SetDataModeToBinary() elif filetype == "xdmf2": writer = vtk.vtkXdmfWriter() elif filetype == "xdmf3": writer = vtk.vtkXdmf3Writer() else: assert filetype == "exodus", f"Unknown file type '{filename}'." writer = vtk.vtkExodusIIWriter() # if the mesh contains vtkmodeldata information, make use of it # and write out all time steps. writer.WriteAllTimeStepsOn() return writer def write(filetype, filename, mesh): import vtk def _create_vtkarray(X, name): array = vtk.util.numpy_support.numpy_to_vtk(X, deep=1) array.SetName(name) return array # assert data integrity for val in mesh.point_data.values(): assert len(val) == len(mesh.points), "Point data mismatch." for key, value in mesh.cell_data.items(): assert key in mesh.cells, "Cell data without cell" for key2 in value: assert len(value[key2]) == len(mesh.cells[key]), "Cell data mismatch." vtk_mesh = _generate_vtk_mesh(mesh.points, mesh.cells) # add point data pd = vtk_mesh.GetPointData() for name, X in mesh.point_data.items(): # There is a naming inconsistency in VTK when it comes to multivectors # in Exodus files: # If a vector 'v' has two components, they are called 'v_x', 'v_y' # (note the underscore), if it has three, then they are called 'vx', # 'vy', 'vz'. See bug . # For VT{K,U} files, no underscore is ever added. pd.AddArray(_create_vtkarray(X, name)) # Add cell data. # The cell_data is structured like # # cell_type -> # key -> array # key -> array # [...] # cell_type -> # key -> array # key -> array # [...] # [...] # # VTK expects one array for each `key`, so assemble the keys across all # mesh_types. This requires each key to be present for each mesh_type, of # course. all_keys = [] for cell_type in mesh.cell_data: all_keys += mesh.cell_data[cell_type].keys() # create unified cell data for key in all_keys: for cell_type in mesh.cell_data: assert key in mesh.cell_data[cell_type] unified_cell_data = { key: np.concatenate([value[key] for value in mesh.cell_data.values()]) for key in all_keys } # add the array data to the mesh cd = vtk_mesh.GetCellData() for name, array in unified_cell_data.items(): cd.AddArray(_create_vtkarray(array, name)) # add field data fd = vtk_mesh.GetFieldData() for key, value in mesh.field_data.items(): fd.AddArray(_create_vtkarray(value, key)) writer = _get_writer(filetype, filename) writer.SetFileName(filename) try: writer.SetInput(vtk_mesh) except AttributeError: writer.SetInputData(vtk_mesh) writer.Write() return def _generate_vtk_mesh(points, cells): import vtk from vtk.util import numpy as numpy_support mesh = vtk.vtkUnstructuredGrid() # set points vtk_points = vtk.vtkPoints() # Not using a deep copy here results in a segfault. vtk_array = numpy_support.numpy_to_vtk(points, deep=True) vtk_points.SetData(vtk_array) mesh.SetPoints(vtk_points) # Set cells. meshio_to_vtk_type = {y: x for x, y in vtk_to_meshio_type.items()} # create cell_array. It's a one-dimensional vector with # (num_points2, p0, p1, ... ,pk, numpoints1, p10, p11, ..., p1k, ... cell_types = [] cell_offsets = [] cell_connectivity = [] len_array = 0 for meshio_type, data in cells.items(): numcells, num_local_nodes = data.shape vtk_type = meshio_to_vtk_type[meshio_type] # add cell types cell_types.append(np.empty(numcells, dtype=np.ubyte)) cell_types[-1].fill(vtk_type) # add cell offsets cell_offsets.append( np.arange( len_array, len_array + numcells * (num_local_nodes + 1), num_local_nodes + 1, dtype=np.int64, ) ) cell_connectivity.append( np.c_[num_local_nodes * np.ones(numcells, dtype=data.dtype), data].flatten() ) len_array += len(cell_connectivity[-1]) cell_types = np.concatenate(cell_types) cell_offsets = np.concatenate(cell_offsets) cell_connectivity = np.concatenate(cell_connectivity) connectivity = vtk.util.numpy_support.numpy_to_vtkIdTypeArray( cell_connectivity.astype(np.int64), deep=1 ) # wrap the data into a vtkCellArray cell_array = vtk.vtkCellArray() cell_array.SetCells(len(cell_types), connectivity) # Add cell data to the mesh mesh.SetCells( numpy_support.numpy_to_vtk( cell_types, deep=1, array_type=vtk.vtkUnsignedCharArray().GetDataType() ), numpy_support.numpy_to_vtk( cell_offsets, deep=1, array_type=vtk.vtkIdTypeArray().GetDataType() ), cell_array, ) return mesh tests/meshes/000077500000000000000000000000001456244072500135155ustar00rootroot00000000000000tests/meshes/abaqus/000077500000000000000000000000001456244072500147715ustar00rootroot00000000000000tests/meshes/abaqus/README.md000066400000000000000000000002761456244072500162550ustar00rootroot00000000000000* `UUea.inp`: From http://www-h.eng.cam.ac.uk/help/programs/fe/abaqus/faq68/txt/UUea.inp.txt * `nle1xf3c.inp`: From https://abaqus-docs.mit.edu/2017/English/SIMAINPRefResources/nle1xf3c.inp tests/meshes/abaqus/UUea.inp000066400000000000000000000162521456244072500163460ustar00rootroot00000000000000*Heading ** Job name: UUa Model name: Model-2 ** Generated by: Abaqus/CAE 6.11-1 *Preprint, echo=NO, model=NO, history=NO, contact=NO ** ** PARTS ** *Part, name=Part-1 *End Part ** ** ** ASSEMBLY ** *Assembly, name=Assembly ** *Instance, name=Part-1-1, part=Part-1 *Node 1, 0., 0. 2, 10., 0. 3, 20., 0. 4, 30., 0. 5, 40., 0. 6, 50., 0. 7, 0., 10. 8, 10., 10. 9, 20., 10. 10, 30., 10. 11, 40., 10. 12, 50., 10. 13, 0., 20. 14, 10., 20. 15, 20., 20. 16, 30., 20. 17, 40., 20. 18, 50., 20. 19, 0., 30. 20, 10., 30. 21, 20., 30. 22, 30., 30. 23, 40., 30. 24, 50., 30. 25, 0., 40. 26, 10., 40. 27, 20., 40. 28, 30., 40. 29, 40., 40. 30, 50., 40. 31, 0., 50. 32, 10., 50. 33, 20., 50. 34, 30., 50. 35, 40., 50. 36, 50., 50. 37, 0., 60. 38, 10., 60. 39, 20., 60. 40, 30., 60. 41, 40., 60. 42, 50., 60. 43, 0., 70. 44, 10., 70. 45, 20., 70. 46, 30., 70. 47, 40., 70. 48, 50., 70. 49, 0., 80. 50, 10., 80. 51, 20., 80. 52, 30., 80. 53, 40., 80. 54, 50., 80. 55, 0., 90. 56, 10., 90. 57, 20., 90. 58, 30., 90. 59, 40., 90. 60, 50., 90. 61, 0., 100. 62, 10., 100. 63, 20., 100. 64, 30., 100. 65, 40., 100. 66, 50., 100. *Element, type=CAX4P 1, 1, 2, 8, 7 2, 2, 3, 9, 8 3, 3, 4, 10, 9 4, 4, 5, 11, 10 5, 5, 6, 12, 11 6, 7, 8, 14, 13 7, 8, 9, 15, 14 8, 9, 10, 16, 15 9, 10, 11, 17, 16 10, 11, 12, 18, 17 11, 13, 14, 20, 19 12, 14, 15, 21, 20 13, 15, 16, 22, 21 14, 16, 17, 23, 22 15, 17, 18, 24, 23 16, 19, 20, 26, 25 17, 20, 21, 27, 26 18, 21, 22, 28, 27 19, 22, 23, 29, 28 20, 23, 24, 30, 29 21, 25, 26, 32, 31 22, 26, 27, 33, 32 23, 27, 28, 34, 33 24, 28, 29, 35, 34 25, 29, 30, 36, 35 26, 31, 32, 38, 37 27, 32, 33, 39, 38 28, 33, 34, 40, 39 29, 34, 35, 41, 40 30, 35, 36, 42, 41 31, 37, 38, 44, 43 32, 38, 39, 45, 44 33, 39, 40, 46, 45 34, 40, 41, 47, 46 35, 41, 42, 48, 47 36, 43, 44, 50, 49 37, 44, 45, 51, 50 38, 45, 46, 52, 51 39, 46, 47, 53, 52 40, 47, 48, 54, 53 41, 49, 50, 56, 55 42, 50, 51, 57, 56 43, 51, 52, 58, 57 44, 52, 53, 59, 58 45, 53, 54, 60, 59 46, 55, 56, 62, 61 47, 56, 57, 63, 62 48, 57, 58, 64, 63 49, 58, 59, 65, 64 50, 59, 60, 66, 65 *Nset, nset=_PickedSet2, internal, generate 1, 66, 1 *Elset, elset=_PickedSet2, internal, generate 1, 50, 1 ** Section: Section-1 *Solid Section, elset=_PickedSet2, material=Material-1 , *End Instance ** *Nset, nset=_PickedSet7, internal, instance=Part-1-1, generate 1, 61, 6 *Elset, elset=_PickedSet7, internal, instance=Part-1-1, generate 1, 46, 5 *Nset, nset=_PickedSet8, internal, instance=Part-1-1, generate 1, 6, 1 *Elset, elset=_PickedSet8, internal, instance=Part-1-1, generate 1, 5, 1 *Nset, nset=_PickedSet14, internal, instance=Part-1-1, generate 61, 66, 1 *Elset, elset=_PickedSet14, internal, instance=Part-1-1, generate 46, 50, 1 *Nset, nset=_PickedSet15, internal, instance=Part-1-1, generate 1, 66, 1 *Elset, elset=_PickedSet15, internal, instance=Part-1-1, generate 1, 50, 1 *Nset, nset=_PickedSet16, internal, instance=Part-1-1, generate 1, 66, 1 *Elset, elset=_PickedSet16, internal, instance=Part-1-1, generate 1, 50, 1 *Nset, nset=_PickedSet17, internal, instance=Part-1-1, generate 1, 66, 1 *Elset, elset=_PickedSet17, internal, instance=Part-1-1, generate 1, 50, 1 *Elset, elset=__PickedSurf12_S3, internal, instance=Part-1-1, generate 46, 50, 1 *Surface, type=ELEMENT, name=_PickedSurf12, internal __PickedSurf12_S3, S3 *Elset, elset=__PickedSurf13_S2, internal, instance=Part-1-1, generate 5, 50, 5 *Surface, type=ELEMENT, name=_PickedSurf13, internal __PickedSurf13_S2, S2 *Elset, elset=__PickedSurf18_S3, internal, instance=Part-1-1, generate 46, 50, 1 *Surface, type=ELEMENT, name=_PickedSurf18, internal __PickedSurf18_S3, S3 *End Assembly *Amplitude, name=Amp-1 0., 0., 1., 1. *Amplitude, name=Amp-2 0., 0., 1., 1. ** ** MATERIALS ** *Material, name=Material-1 *Density 2.7e-06, *Elastic,dependencies=1 45., 0.2, 0. 75., 0.2, 100. *Permeability, specific=10. 1e-08, 0.3 *Mohr Coulomb, dependencies=1 30.,10., , 0. 40.,20., , 100. *Mohr Coulomb Hardening 0.2, 0., 0.4, 0.05, 0.6, 0.09, ** ** BOUNDARY CONDITIONS ** ** Name: Bottom-nodes Type: Symmetry/Antisymmetry/Encastre *Boundary _PickedSet8, YSYMM ** Name: Side-nodes Type: Symmetry/Antisymmetry/Encastre *Boundary _PickedSet7, XSYMM ** ** PREDEFINED FIELDS ** ** Name: Predefined Field-1 Type: Geostatic stress *Initial Conditions, type=STRESS, GEOSTATIC _PickedSet15, -0.221, 0., -0.221, 100., 1., 1. ** Name: Predefined Field-2 Type: Void ratio *Initial Conditions, TYPE=RATIO _PickedSet16, 0.3 ** Name: Predefined Field-3 Type: Pore pressure *Initial Conditions, TYPE=PORE PRESSURE _PickedSet17, 1. ** ---------------------------------------------------------------- ** ** STEP: Step-1 ** *Step, name=Step-1 *Geostatic ** *FIELD, VARIABLE=1, USER ** ** ** LOADS ** ** Name: Side-Confining-Stress Type: Pressure *Dsload _PickedSurf13, P, 1.221 ** Name: Top-Confining-Stress Type: Pressure *Dsload _PickedSurf12, P, 1.221 ** ** OUTPUT REQUESTS ** *Restart, write, frequency=0 ** ** FIELD OUTPUT: F-Output-1 ** *Output, field, variable=PRESELECT ** ** HISTORY OUTPUT: H-Output-1 ** *Output, history, variable=PRESELECT *End Step ** ---------------------------------------------------------------- ** ** STEP: Step-2 ** *Step, name=Step-2 *Soils, consolidation, end=PERIOD, utol=1000. 0.01, 1., 1e-05, 0.01, ** ** BOUNDARY CONDITIONS ** ** Name: BC-4 Type: Displacement/Rotation *Boundary, amplitude=Amp-1 _PickedSet14, 2, 2, -50. ** ** OUTPUT REQUESTS ** *Restart, write, frequency=0 ** ** FIELD OUTPUT: F-Output-1 ** *Output, field, variable=PRESELECT ** ** HISTORY OUTPUT: H-Output-1 ** *Output, history, variable=PRESELECT *End Step tests/meshes/abaqus/element_elset.inp000066400000000000000000000003301456244072500203220ustar00rootroot00000000000000*Heading Abaqus DataFile Version 6.14 *Node 1, 1, 0, 0 2, 1, 1, 0 3, 2, 0.5, 0 4, 0, 0.5, 0 *Element, type=S3, ELSET=right 1, 1, 2, 3 *Element, type=S3, ELSET=left 2, 1, 2, 4 *Elset, elset=all right lefttests/meshes/abaqus/nle1xf3c.inp000066400000000000000000000034721456244072500171320ustar00rootroot00000000000000*HEADING : NAFEMS TEST LE1, Plane Stress Elements -- Elliptic Membr. [CPS3] *RESTART,WRITE *NODE, NSET=CF000 1, 0.000000000E+00, 0.100000000E+01, 0.000000000E+00 2, 0.000000000E+00, 0.187500000E+01, 0.000000000E+00 3, 0.000000000E+00, 0.275000000E+01, 0.000000000E+00 4, 0.116500008E+01, 0.812829971E+00, 0.000000000E+00 5, 0.147400010E+01, 0.155601501E+01, 0.000000000E+00 6, 0.178300011E+01, 0.229920006E+01, 0.000000000E+00 7, 0.178302014E+01, 0.452999949E+00, 0.000000000E+00 8, 0.230790997E+01, 0.900500059E+00, 0.000000000E+00 9, 0.283279991E+01, 0.134800017E+01, 0.000000000E+00 10, 0.200000000E+01, 0.000000000E+00, 0.000000000E+00 11, 0.262500000E+01, 0.000000000E+00, 0.000000000E+00 12, 0.325000000E+01, 0.000000000E+00, 0.000000000E+00 *ELEMENT, TYPE=CPS3, ELSET=M001P001 1, 5, 2, 1 2, 1, 4, 5 3, 8, 5, 4 4, 4, 7, 8 5, 11, 8, 7 6, 7, 10, 11 7, 6, 3, 2 8, 2, 5, 6 9, 9, 6, 5 10, 5, 8, 9 11, 12, 9, 8 12, 8, 11, 12 *ELSET,ELSET=LOAD 7,9,11 *ELSET,ELSET=PR 6, *SOLID SECTION, ELSET=M001P001, MATERIAL=M001P001 0.1000 , 5 *MATERIAL, NAME=M001P001 *ELASTIC, TYPE=ISO 0.2100E+06, 0.3000 , 0.0000E+00 *STEP, AMP=RAMP LOAD CASE 1 *STATIC *DLOAD, OP=NEW LOAD,P1,-10.0 *BOUNDARY, OP=NEW 1, 1, , 0.0000E+00 2, 1, , 0.0000E+00 3, 1, , 0.0000E+00 10, 2, , 0.0000E+00 11, 2, , 0.0000E+00 12, 2, , 0.0000E+00 *EL FILE, ELSET=PR, POSITION=AVERAGED AT NODES S, *NODE FILE, GLOBAL=YES U, *OUTPUT,FIELD *NODE OUTPUT U, *EL PRINT,POS=AVERAGED AT NODES *END STEP tests/meshes/abaqus/wInclude_bulk.inp000066400000000000000000000007431456244072500202740ustar00rootroot00000000000000*NODE 1, 0.0, 0.0, 0.0 2, 1.0, 0.0, 0.0 3, 0.5, 0.0, 0.0 *ELEMENT, type=B31 3, 1, 3 4, 3, 2 *Elset, elset=elBm_set 3, 4 ** Section: elBm_set Profile: elBm_set *Beam Section, elset=elBm_set, material=Bm_mat, temperature=GRADIENT, section=I 0.15, 0.3, 0.15, 0.15, 0.0107, 0.0107, 0.0071 0.0, -1.0, 0.0tests/meshes/abaqus/wInclude_main.inp000066400000000000000000000003121456244072500202530ustar00rootroot00000000000000*Heading ** meshio with *include example *Preprint, echo=NO, model=NO, history=NO, contact=NO *constraint controls, print=yes *Part, name=ParametricModel *INCLUDE,INPUT=wInclude_bulk.inp *End Parttests/meshes/flac3d/000077500000000000000000000000001456244072500146515ustar00rootroot00000000000000tests/meshes/flac3d/flac3d_mesh_ex.f3grid000066400000000000000000000420241456244072500206170ustar00rootroot00000000000000* FLAC3D grid produced by FLAC3D 7.00 Release 118 * Wed Aug 19 01:28:26 2020 * GRIDPOINTS G 1 0.00000000000000e+00 0.00000000000000e+00 0.00000000000000e+00 G 2 3.33333333333333e-01 0.00000000000000e+00 0.00000000000000e+00 G 3 0.00000000000000e+00 3.33333333333333e-01 0.00000000000000e+00 G 4 0.00000000000000e+00 0.00000000000000e+00 3.33333333333333e-01 G 5 3.33333333333333e-01 3.33333333333333e-01 0.00000000000000e+00 G 6 0.00000000000000e+00 3.33333333333333e-01 3.33333333333333e-01 G 7 3.33333333333333e-01 0.00000000000000e+00 3.33333333333333e-01 G 8 3.33333333333333e-01 3.33333333333333e-01 3.33333333333333e-01 G 9 6.66666666666667e-01 0.00000000000000e+00 0.00000000000000e+00 G 10 6.66666666666667e-01 3.33333333333333e-01 0.00000000000000e+00 G 11 6.66666666666667e-01 0.00000000000000e+00 3.33333333333333e-01 G 12 6.66666666666667e-01 3.33333333333333e-01 3.33333333333333e-01 G 13 1.00000000000000e+00 0.00000000000000e+00 0.00000000000000e+00 G 14 1.00000000000000e+00 3.33333333333333e-01 0.00000000000000e+00 G 15 1.00000000000000e+00 0.00000000000000e+00 3.33333333333333e-01 G 16 1.00000000000000e+00 3.33333333333333e-01 3.33333333333333e-01 G 17 0.00000000000000e+00 6.66666666666667e-01 0.00000000000000e+00 G 18 3.33333333333333e-01 6.66666666666667e-01 0.00000000000000e+00 G 19 0.00000000000000e+00 6.66666666666667e-01 3.33333333333333e-01 G 20 3.33333333333333e-01 6.66666666666667e-01 3.33333333333333e-01 G 21 6.66666666666667e-01 6.66666666666667e-01 0.00000000000000e+00 G 22 6.66666666666667e-01 6.66666666666667e-01 3.33333333333333e-01 G 23 1.00000000000000e+00 6.66666666666667e-01 0.00000000000000e+00 G 24 1.00000000000000e+00 6.66666666666667e-01 3.33333333333333e-01 G 25 0.00000000000000e+00 1.00000000000000e+00 0.00000000000000e+00 G 26 3.33333333333333e-01 1.00000000000000e+00 0.00000000000000e+00 G 27 0.00000000000000e+00 1.00000000000000e+00 3.33333333333333e-01 G 28 3.33333333333333e-01 1.00000000000000e+00 3.33333333333333e-01 G 29 6.66666666666667e-01 1.00000000000000e+00 0.00000000000000e+00 G 30 6.66666666666667e-01 1.00000000000000e+00 3.33333333333333e-01 G 31 1.00000000000000e+00 1.00000000000000e+00 0.00000000000000e+00 G 32 1.00000000000000e+00 1.00000000000000e+00 3.33333333333333e-01 G 33 0.00000000000000e+00 0.00000000000000e+00 6.66666666666667e-01 G 34 0.00000000000000e+00 3.33333333333333e-01 6.66666666666667e-01 G 35 3.33333333333333e-01 0.00000000000000e+00 6.66666666666667e-01 G 36 3.33333333333333e-01 3.33333333333333e-01 6.66666666666667e-01 G 37 6.66666666666667e-01 0.00000000000000e+00 6.66666666666667e-01 G 38 6.66666666666667e-01 3.33333333333333e-01 6.66666666666667e-01 G 39 1.00000000000000e+00 0.00000000000000e+00 6.66666666666667e-01 G 40 1.00000000000000e+00 3.33333333333333e-01 6.66666666666667e-01 G 41 0.00000000000000e+00 6.66666666666667e-01 6.66666666666667e-01 G 42 3.33333333333333e-01 6.66666666666667e-01 6.66666666666667e-01 G 43 6.66666666666667e-01 6.66666666666667e-01 6.66666666666667e-01 G 44 1.00000000000000e+00 6.66666666666667e-01 6.66666666666667e-01 G 45 0.00000000000000e+00 1.00000000000000e+00 6.66666666666667e-01 G 46 3.33333333333333e-01 1.00000000000000e+00 6.66666666666667e-01 G 47 6.66666666666667e-01 1.00000000000000e+00 6.66666666666667e-01 G 48 1.00000000000000e+00 1.00000000000000e+00 6.66666666666667e-01 G 49 0.00000000000000e+00 0.00000000000000e+00 1.00000000000000e+00 G 50 0.00000000000000e+00 3.33333333333333e-01 1.00000000000000e+00 G 51 3.33333333333333e-01 0.00000000000000e+00 1.00000000000000e+00 G 52 3.33333333333333e-01 3.33333333333333e-01 1.00000000000000e+00 G 53 6.66666666666667e-01 0.00000000000000e+00 1.00000000000000e+00 G 54 6.66666666666667e-01 3.33333333333333e-01 1.00000000000000e+00 G 55 1.00000000000000e+00 0.00000000000000e+00 1.00000000000000e+00 G 56 1.00000000000000e+00 3.33333333333333e-01 1.00000000000000e+00 G 57 0.00000000000000e+00 6.66666666666667e-01 1.00000000000000e+00 G 58 3.33333333333333e-01 6.66666666666667e-01 1.00000000000000e+00 G 59 6.66666666666667e-01 6.66666666666667e-01 1.00000000000000e+00 G 60 1.00000000000000e+00 6.66666666666667e-01 1.00000000000000e+00 G 61 0.00000000000000e+00 1.00000000000000e+00 1.00000000000000e+00 G 62 3.33333333333333e-01 1.00000000000000e+00 1.00000000000000e+00 G 63 6.66666666666667e-01 1.00000000000000e+00 1.00000000000000e+00 G 64 1.00000000000000e+00 1.00000000000000e+00 1.00000000000000e+00 G 65 1.66666666666667e-01 1.66666666666667e-01 1.16666666666667e+00 G 66 1.66666666666667e-01 3.88888888888889e-01 1.16666666666667e+00 G 67 3.88888888888889e-01 1.66666666666667e-01 1.16666666666667e+00 G 68 3.88888888888889e-01 3.88888888888889e-01 1.16666666666667e+00 G 69 6.11111111111111e-01 1.66666666666667e-01 1.16666666666667e+00 G 70 6.11111111111111e-01 3.88888888888889e-01 1.16666666666667e+00 G 71 8.33333333333333e-01 1.66666666666667e-01 1.16666666666667e+00 G 72 8.33333333333333e-01 3.88888888888889e-01 1.16666666666667e+00 G 73 1.66666666666667e-01 6.11111111111111e-01 1.16666666666667e+00 G 74 3.88888888888889e-01 6.11111111111111e-01 1.16666666666667e+00 G 75 6.11111111111111e-01 6.11111111111111e-01 1.16666666666667e+00 G 76 8.33333333333333e-01 6.11111111111111e-01 1.16666666666667e+00 G 77 1.66666666666667e-01 8.33333333333333e-01 1.16666666666667e+00 G 78 3.88888888888889e-01 8.33333333333333e-01 1.16666666666667e+00 G 79 6.11111111111111e-01 8.33333333333333e-01 1.16666666666667e+00 G 80 8.33333333333333e-01 8.33333333333333e-01 1.16666666666667e+00 G 81 3.33333333333333e-01 3.33333333333333e-01 1.33333333333333e+00 G 82 3.33333333333333e-01 4.44444444444444e-01 1.33333333333333e+00 G 83 4.44444444444444e-01 3.33333333333333e-01 1.33333333333333e+00 G 84 4.44444444444444e-01 4.44444444444444e-01 1.33333333333333e+00 G 85 5.55555555555556e-01 3.33333333333333e-01 1.33333333333333e+00 G 86 5.55555555555556e-01 4.44444444444444e-01 1.33333333333333e+00 G 87 6.66666666666667e-01 3.33333333333333e-01 1.33333333333333e+00 G 88 6.66666666666667e-01 4.44444444444444e-01 1.33333333333333e+00 G 89 3.33333333333333e-01 5.55555555555556e-01 1.33333333333333e+00 G 90 4.44444444444444e-01 5.55555555555556e-01 1.33333333333333e+00 G 91 5.55555555555556e-01 5.55555555555556e-01 1.33333333333333e+00 G 92 6.66666666666667e-01 5.55555555555556e-01 1.33333333333333e+00 G 93 3.33333333333333e-01 6.66666666666667e-01 1.33333333333333e+00 G 94 4.44444444444444e-01 6.66666666666667e-01 1.33333333333333e+00 G 95 5.55555555555556e-01 6.66666666666667e-01 1.33333333333333e+00 G 96 6.66666666666667e-01 6.66666666666667e-01 1.33333333333333e+00 G 97 5.00000000000000e-01 5.00000000000000e-01 1.50000000000000e+00 G 98 1.33333333333333e+00 0.00000000000000e+00 0.00000000000000e+00 G 99 1.33333333333333e+00 3.33333333333333e-01 0.00000000000000e+00 G 100 1.22222222222222e+00 0.00000000000000e+00 3.33333333333333e-01 G 101 1.22222222222222e+00 3.33333333333333e-01 3.33333333333333e-01 G 102 1.66666666666667e+00 0.00000000000000e+00 0.00000000000000e+00 G 103 1.66666666666667e+00 3.33333333333333e-01 0.00000000000000e+00 G 104 1.44444444444444e+00 0.00000000000000e+00 3.33333333333333e-01 G 105 1.44444444444444e+00 3.33333333333333e-01 3.33333333333333e-01 G 106 2.00000000000000e+00 0.00000000000000e+00 0.00000000000000e+00 G 107 2.00000000000000e+00 3.33333333333333e-01 0.00000000000000e+00 G 108 1.66666666666667e+00 0.00000000000000e+00 3.33333333333333e-01 G 109 1.66666666666667e+00 3.33333333333333e-01 3.33333333333333e-01 G 110 1.33333333333333e+00 6.66666666666667e-01 0.00000000000000e+00 G 111 1.22222222222222e+00 6.66666666666667e-01 3.33333333333333e-01 G 112 1.66666666666667e+00 6.66666666666667e-01 0.00000000000000e+00 G 113 1.44444444444444e+00 6.66666666666667e-01 3.33333333333333e-01 G 114 2.00000000000000e+00 6.66666666666667e-01 0.00000000000000e+00 G 115 1.66666666666667e+00 6.66666666666667e-01 3.33333333333333e-01 G 116 1.33333333333333e+00 1.00000000000000e+00 0.00000000000000e+00 G 117 1.22222222222222e+00 1.00000000000000e+00 3.33333333333333e-01 G 118 1.66666666666667e+00 1.00000000000000e+00 0.00000000000000e+00 G 119 1.44444444444444e+00 1.00000000000000e+00 3.33333333333333e-01 G 120 2.00000000000000e+00 1.00000000000000e+00 0.00000000000000e+00 G 121 1.66666666666667e+00 1.00000000000000e+00 3.33333333333333e-01 G 122 1.11111111111111e+00 0.00000000000000e+00 6.66666666666667e-01 G 123 1.11111111111111e+00 3.33333333333333e-01 6.66666666666667e-01 G 124 1.22222222222222e+00 0.00000000000000e+00 6.66666666666667e-01 G 125 1.22222222222222e+00 3.33333333333333e-01 6.66666666666667e-01 G 126 1.33333333333333e+00 0.00000000000000e+00 6.66666666666667e-01 G 127 1.33333333333333e+00 3.33333333333333e-01 6.66666666666667e-01 G 128 1.11111111111111e+00 6.66666666666667e-01 6.66666666666667e-01 G 129 1.22222222222222e+00 6.66666666666667e-01 6.66666666666667e-01 G 130 1.33333333333333e+00 6.66666666666667e-01 6.66666666666667e-01 G 131 1.11111111111111e+00 1.00000000000000e+00 6.66666666666667e-01 G 132 1.22222222222222e+00 1.00000000000000e+00 6.66666666666667e-01 G 133 1.33333333333333e+00 1.00000000000000e+00 6.66666666666667e-01 G 134 0.00000000000000e+00 5.00000000000000e-01 1.50000000000000e+00 G 135 0.00000000000000e+00 3.33333333333333e-01 1.33333333333333e+00 G 136 0.00000000000000e+00 6.66666666666667e-01 1.33333333333333e+00 G 137 1.66666666666667e-01 5.00000000000000e-01 1.50000000000000e+00 G 138 0.00000000000000e+00 5.55555555555556e-01 1.22222222222222e+00 G 139 1.66666666666667e-01 6.11111111111111e-01 1.38888888888889e+00 G 140 1.66666666666667e-01 3.88888888888889e-01 1.38888888888889e+00 G 141 1.66666666666667e-01 5.37037037037037e-01 1.31481481481481e+00 G 142 0.00000000000000e+00 1.66666666666667e-01 1.16666666666667e+00 G 143 0.00000000000000e+00 4.44444444444444e-01 1.11111111111111e+00 G 144 1.66666666666667e-01 2.77777777777778e-01 1.27777777777778e+00 G 145 1.66666666666667e-01 4.62962962962963e-01 1.24074074074074e+00 G 146 0.00000000000000e+00 8.33333333333333e-01 1.16666666666667e+00 G 147 0.00000000000000e+00 7.77777777777778e-01 1.11111111111111e+00 G 148 1.66666666666667e-01 7.22222222222222e-01 1.27777777777778e+00 G 149 1.66666666666667e-01 6.85185185185185e-01 1.24074074074074e+00 G 150 0.00000000000000e+00 7.22222222222222e-01 1.05555555555556e+00 G 151 1.66666666666667e-01 6.48148148148148e-01 1.20370370370370e+00 G 152 3.33333333333333e-01 5.00000000000000e-01 1.50000000000000e+00 G 153 3.33333333333333e-01 5.55555555555556e-01 1.44444444444444e+00 G 154 3.33333333333333e-01 4.44444444444444e-01 1.44444444444444e+00 G 155 3.33333333333333e-01 5.18518518518518e-01 1.40740740740741e+00 G 156 3.33333333333333e-01 3.88888888888889e-01 1.38888888888889e+00 G 157 3.33333333333333e-01 4.81481481481481e-01 1.37037037037037e+00 G 158 3.33333333333333e-01 6.11111111111111e-01 1.38888888888889e+00 G 159 3.33333333333333e-01 5.92592592592593e-01 1.37037037037037e+00 G 160 3.33333333333333e-01 5.74074074074074e-01 1.35185185185185e+00 * ZONES Z B8 1 1 2 3 4 5 6 7 8 Z B8 2 2 9 5 7 10 8 11 12 Z B8 3 9 13 10 11 14 12 15 16 Z B8 4 3 5 17 6 18 19 8 20 Z B8 5 5 10 18 8 21 20 12 22 Z B8 6 10 14 21 12 23 22 16 24 Z B8 7 17 18 25 19 26 27 20 28 Z B8 8 18 21 26 20 29 28 22 30 Z B8 9 21 23 29 22 31 30 24 32 Z B8 10 4 7 6 33 8 34 35 36 Z B8 11 7 11 8 35 12 36 37 38 Z B8 12 11 15 12 37 16 38 39 40 Z B8 13 6 8 19 34 20 41 36 42 Z B8 14 8 12 20 36 22 42 38 43 Z B8 15 12 16 22 38 24 43 40 44 Z B8 16 19 20 27 41 28 45 42 46 Z B8 17 20 22 28 42 30 46 43 47 Z B8 18 22 24 30 43 32 47 44 48 Z B8 19 33 35 34 49 36 50 51 52 Z B8 20 35 37 36 51 38 52 53 54 Z B8 21 37 39 38 53 40 54 55 56 Z B8 22 34 36 41 50 42 57 52 58 Z B8 23 36 38 42 52 43 58 54 59 Z B8 24 38 40 43 54 44 59 56 60 Z B8 25 41 42 45 57 46 61 58 62 Z B8 26 42 43 46 58 47 62 59 63 Z B8 27 43 44 47 59 48 63 60 64 Z B8 28 49 51 50 65 52 66 67 68 Z B8 29 51 53 52 67 54 68 69 70 Z B8 30 53 55 54 69 56 70 71 72 Z B8 31 50 52 57 66 58 73 68 74 Z B8 32 52 54 58 68 59 74 70 75 Z B8 33 54 56 59 70 60 75 72 76 Z B8 34 57 58 61 73 62 77 74 78 Z B8 35 58 59 62 74 63 78 75 79 Z B8 36 59 60 63 75 64 79 76 80 Z B8 37 65 67 66 81 68 82 83 84 Z B8 38 67 69 68 83 70 84 85 86 Z B8 39 69 71 70 85 72 86 87 88 Z B8 40 66 68 73 82 74 89 84 90 Z B8 41 68 70 74 84 75 90 86 91 Z B8 42 70 72 75 86 76 91 88 92 Z B8 43 73 74 77 89 78 93 90 94 Z B8 44 74 75 78 90 79 94 91 95 Z B8 45 75 76 79 91 80 95 92 96 Z P5 46 81 83 82 97 84 Z P5 47 83 85 84 97 86 Z P5 48 85 87 86 97 88 Z P5 49 82 84 89 97 90 Z P5 50 84 86 90 97 91 Z P5 51 86 88 91 97 92 Z P5 52 89 90 93 97 94 Z P5 53 90 91 94 97 95 Z P5 54 91 92 95 97 96 Z B8 55 13 98 14 15 99 16 100 101 Z B8 56 98 102 99 100 103 101 104 105 Z B8 57 102 106 103 104 107 105 108 109 Z B8 58 14 99 23 16 110 24 101 111 Z B8 59 99 103 110 101 112 111 105 113 Z B8 60 103 107 112 105 114 113 109 115 Z B8 61 23 110 31 24 116 32 111 117 Z B8 62 110 112 116 111 118 117 113 119 Z B8 63 112 114 118 113 120 119 115 121 Z B8 64 15 100 16 39 101 40 122 123 Z B8 65 100 104 101 122 105 123 124 125 Z B8 66 104 108 105 124 109 125 126 127 Z B8 67 16 101 24 40 111 44 123 128 Z B8 68 101 105 111 123 113 128 125 129 Z B8 69 105 109 113 125 115 129 127 130 Z B8 70 24 111 32 44 117 48 128 131 Z B8 71 111 113 117 128 119 131 129 132 Z B8 72 113 115 119 129 121 132 130 133 Z W6 73 39 122 40 55 123 56 Z W6 74 122 124 123 55 125 56 Z W6 75 124 126 125 55 127 56 Z W6 76 40 123 44 56 128 60 Z W6 77 123 125 128 56 129 60 Z W6 78 125 127 129 56 130 60 Z W6 79 44 128 48 60 131 64 Z W6 80 128 129 131 60 132 64 Z W6 81 129 130 132 60 133 64 Z B8 82 134 135 136 137 138 139 140 141 Z B8 83 135 142 138 140 143 141 144 145 Z B8 84 142 49 143 144 50 145 65 66 Z B8 85 136 138 146 139 147 148 141 149 Z B8 86 138 143 147 141 150 149 145 151 Z B8 87 143 50 150 145 57 151 66 73 Z W6 88 148 149 146 77 147 61 Z W6 89 149 151 147 77 150 61 Z W6 90 151 73 150 77 57 61 Z B8 91 137 140 139 152 141 153 154 155 Z B8 92 140 144 141 154 145 155 156 157 Z B8 93 144 65 145 156 66 157 81 82 Z B8 94 139 141 148 153 149 158 155 159 Z B8 95 141 145 149 155 151 159 157 160 Z B8 96 145 66 151 157 73 160 82 89 Z W6 97 158 159 148 93 149 77 Z W6 98 159 160 149 93 151 77 Z W6 99 160 89 151 93 73 77 Z P5 100 152 154 153 97 155 Z P5 101 154 156 155 97 157 Z P5 102 156 81 157 97 82 Z P5 103 153 155 158 97 159 Z P5 104 155 157 159 97 160 Z P5 105 157 82 160 97 89 Z T4 106 158 159 93 97 Z T4 107 159 160 93 97 Z T4 108 160 89 93 97 * ZONE GROUPS ZGROUP "Brick1" SLOT "Default" 6 7 4 5 2 3 1 14 15 12 13 10 11 8 9 22 23 20 21 18 19 16 17 26 27 24 25 ZGROUP "Pyramid2" SLOT "Default" 38 39 36 37 34 35 32 33 46 47 44 45 42 43 40 41 54 52 30 53 31 50 28 51 29 48 49 ZGROUP "Tetrahedron4" SLOT "Default" 101 98 99 96 97 108 86 87 106 84 107 85 104 82 105 83 94 95 92 93 90 91 88 89 102 103 100 ZGROUP "Wedge3" SLOT "Default" 56 78 57 79 76 77 74 75 72 73 80 81 55 70 71 68 62 63 69 60 66 61 67 58 64 59 65 * FACES F Q4 1 1 3 6 4 F Q4 2 3 17 19 6 F Q4 3 17 25 27 19 F Q4 4 4 6 34 33 F Q4 5 6 19 41 34 F Q4 6 19 27 45 41 F Q4 7 33 34 50 49 F Q4 8 34 41 57 50 F Q4 9 41 45 61 57 F Q4 10 135 138 136 134 F Q4 11 142 143 138 135 F Q4 12 49 50 143 142 F Q4 13 138 147 146 136 F Q4 14 143 150 147 138 F Q4 15 50 57 150 143 F T3 16 146 147 61 F T3 17 147 150 61 F T3 18 150 57 61 * FACE GROUPS FGROUP "bottom" SLOT "Default" 6 7 4 5 2 3 1 14 15 12 13 10 11 8 9 18 16 17 tests/meshes/flac3d/flac3d_mesh_ex_bin.f3grid000066400000000000000000000224551456244072500214550ustar00rootroot00000000000000QOUUUUU?OUUUUU?OUUUUU?OUUUUU?OUUUUU?OUUUUU?OUUUUU?OUUUUU?OUUUUU?OUUUUU?OUUUUU?OUUUUU? XUUUUU? XUUUUU?OUUUUU? XUUUUU?OUUUUU? XUUUUU?OUUUUU?OUUUUU? ??OUUUUU??OUUUUU??OUUUUU?OUUUUU?XUUUUU?OUUUUU?XUUUUU?XUUUUU?OUUUUU?OUUUUU?XUUUUU?OUUUUU?XUUUUU?XUUUUU?XUUUUU?XUUUUU?OUUUUU??XUUUUU??XUUUUU?OUUUUU??OUUUUU???OUUUUU?OUUUUU??OUUUUU?XUUUUU??XUUUUU??OUUUUU??? ??OUUUUU?!XUUUUU?"OUUUUU?XUUUUU?#OUUUUU?XUUUUU?$OUUUUU?OUUUUU?XUUUUU?%XUUUUU?XUUUUU?&XUUUUU?OUUUUU?XUUUUU?'?XUUUUU?(?OUUUUU?XUUUUU?)XUUUUU?XUUUUU?*OUUUUU?XUUUUU?XUUUUU?+XUUUUU?XUUUUU?XUUUUU?,?XUUUUU?XUUUUU?-?XUUUUU?.OUUUUU??XUUUUU?/XUUUUU??XUUUUU?0??XUUUUU?1?2OUUUUU??3OUUUUU??4OUUUUU?OUUUUU??5XUUUUU??6XUUUUU?OUUUUU??7??8?OUUUUU??9XUUUUU??:OUUUUU?XUUUUU??;XUUUUU?XUUUUU??<?XUUUUU??=??>OUUUUU????XUUUUU???@???AaUUUUU?aUUUUU??BaUUUUU?;8??C;8?aUUUUU??D;8?;8??E88?aUUUUU??F88?;8??G?aUUUUU??H?;8??IaUUUUU?88??J;8?88??K88?88??L?88??MaUUUUU???N;8???O88???P???QOUUUUU?OUUUUU?FUUUUU?ROUUUUU?qq?FUUUUU?Sqq?OUUUUU?FUUUUU?Tqq?qq?FUUUUU?Uvq?OUUUUU?FUUUUU?Vvq?qq?FUUUUU?WXUUUUU?OUUUUU?FUUUUU?XXUUUUU?qq?FUUUUU?YOUUUUU?vq?FUUUUU?Zqq?vq?FUUUUU?[vq?vq?FUUUUU?\XUUUUU?vq?FUUUUU?]OUUUUU?XUUUUU?FUUUUU?^qq?XUUUUU?FUUUUU?_vq?XUUUUU?FUUUUU?`XUUUUU?XUUUUU?FUUUUU?a???bFUUUUU?cFUUUUU?OUUUUU?d88?OUUUUU?e88?OUUUUU?OUUUUU?f?g?OUUUUU?hqq?OUUUUU?iqq?OUUUUU?OUUUUU?j@k@OUUUUU?l?OUUUUU?m?OUUUUU?OUUUUU?nFUUUUU?XUUUUU?o88?XUUUUU?OUUUUU?p?XUUUUU?qqq?XUUUUU?OUUUUU?r@XUUUUU?s?XUUUUU?OUUUUU?tFUUUUU??u88??OUUUUU?v??wqq??OUUUUU?x@?y??OUUUUU?zmq?XUUUUU?{mq?OUUUUU?XUUUUU?|88?XUUUUU?}88?OUUUUU?XUUUUU?~FUUUUU?XUUUUU?FUUUUU?OUUUUU?XUUUUU?mq?XUUUUU?XUUUUU?88?XUUUUU?XUUUUU?FUUUUU?XUUUUU?XUUUUU?mq??XUUUUU?88??XUUUUU?FUUUUU??XUUUUU???OUUUUU?FUUUUU?XUUUUU?FUUUUU?aUUUUU???vq?88?aUUUUU?88?88?aUUUUU?;8?88?aUUUUU?Kh/?^B{ ?aUUUUU??qq?mq?aUUUUU?vq?&qq?aUUUUU?Kh/????;8?mq?aUUUUU?qq?&qq?aUUUUU?^B{ ??qq?M8?aUUUUU?Kh/?^B?OUUUUU???OUUUUU?vq?qq?OUUUUU?qq?qq?OUUUUU?w %?Xh/?OUUUUU?;8?88?OUUUUU?%?^B{ ?OUUUUU?88?88?OUUUUU?l/?^B{ ?OUUUUU?%^? Kh/?l           !"#$  # $%&   %&'( ")$* $*&+ &+(,)-*.*.+/+ /,0!#"1$234#%$3&456%'&5(678"$)2*94:$&*4+:6;&(+6,;8<)*-9.=:>*+.:/>;?+,/;0?<@132A4BCD354C6DEF576E8FGH249B:IDJ 46:D;JFK!68;F<KHL"9:=I>MJN#:;>J?NKO$;<?K@OLP%ACBQDRST&CEDSFTUV'EGFUHVWX(BDIRJYTZ)DFJTKZV[*FHKVL[X\+IJMYN]Z^,JKNZO^[_-KLO[P_\`.QSRaT/SUTaV0UWVaX1RTYaZ2TVZa[3VX[a\4YZ]a^5Z[^a_6[\_a`7 bcde8bfcdgehi9fjghkilm:cneo;cgnepoiq<gkpirqms=nt ou>nptovuqw?prvqxwsy@d'e(z{Adhezi{|}Bhli|m}~Ce(o,{Deio{q}Eimq}sFo ,u0GoquwHqswyI'z(7{8Jz|{7}8K|~}78L({,8<M{}8<N}8<O,0<@P<@Q<@RST12ABUVW29BIXM=YM=ZIM9=[\]ABQR^_`BIRYa]Mb]McY]IMdaeafQaRgahaiRaYj]ak]alY]aBrick1Default  Pyramid2Default&'$%"# !./,-*+()6452301 Tetrahedron4Defaultebc`alVWjTkUhRiS^_\]Z[XYfgdWedge3Default8N9OLMJKHIPQ7FGD>?E<B=C:@;A"!)"-)!"21")92 )-=9   12 29==9=bottomDefault  tests/meshes/med/000077500000000000000000000000001456244072500142625ustar00rootroot00000000000000tests/meshes/med/README.md000066400000000000000000000032421456244072500155420ustar00rootroot00000000000000`cylinder.med` is first generated by salome 9.2.2. The mesh version is then modified by HDFView by changing the mesh version from 4.0.0 to 3.0.0 so that it can also be read in gmsh. `box.med` is generated by code_aster 13.6 using the following command file. A specific displacement field is prescribed to an orthotropic hexahedral element, and we verify if meshio is able to read the current stress/strain/energy data. ``` DEBUT() mesh = LIRE_MAILLAGE(FORMAT='MED', INFO=2, UNITE=20) mesh = DEFI_GROUP( reuse=mesh, MAILLAGE=mesh, CREA_GROUP_NO=(_F(NOM='Left', NOEUD=('N1', 'N2', 'N3', 'N4')), _F(NOM='Right', NOEUD=('N5', 'N6', 'N7', 'N8')))) model = AFFE_MODELE( AFFE=_F(MODELISATION=('3D', ), PHENOMENE='MECANIQUE', TOUT='OUI'), MAILLAGE=mesh ) mat = DEFI_MATERIAU( ELAS_ORTH=_F(RHO=1.37486e-09, E_L=5329.16, E_T=2418.93, E_N=1746.66, G_LT=1202.6, G_TN=515.638, G_LN=569.752, NU_LT=0.450006, NU_TN=0.564862, NU_LN=0.397544, ALPHA_L=1.0163e-05, ALPHA_T=2.67311e-05, ALPHA_N=6.86122e-05)) load = AFFE_CHAR_MECA( MODELE=model, DDL_IMPO=(_F(GROUP_NO='Left', DX=0, DY=0, DZ=0), _F(GROUP_NO='Right', DX=1, DY=1, DZ=1)) ) fieldmat = AFFE_MATERIAU( AFFE=_F(MATER=(mat, ), TOUT='OUI'), MODELE=model ) resu = MECA_STATIQUE( CHAM_MATER=fieldmat, EXCIT=_F(CHARGE=load), MODELE=model, OPTION='SANS', SOLVEUR=_F(METHODE='MUMPS') ) resu = CALC_CHAMP( reuse=resu, RESULTAT=resu, CONTRAINTE='SIEF_ELNO', DEFORMATION='EPSI_ELNO', ENERGIE=('ENEL_ELEM', 'ENEL_ELNO')) IMPR_RESU( FORMAT='MED', RESU=_F(RESULTAT=resu), UNITE=80 ) FIN() ``` tests/meshes/med/box.med000066400000000000000000000513201456244072500155420ustar00rootroot00000000000000HDF  R0&VOHDR $\$\$\$\x INFOS_GENERALESENS_MAA[',IƧOHDR $\$\$\$\  ! MAJ  ! MIN  ! REL  OHDR $\$\$\$\x meshE녎=OHDR!$\$\$\$\ S3(-0000000000000000001-0000000000000000001&FFRHPy ("BTHDd( FSHDPx(rbBTLF JQZ!TE !Bsm7!7gR%@puy-s0!mCWJ!#J !+X!;HFSSEy#AOCHK descripteur de fichierCODE_ASTER - 13.06.00 - EXPLOITATION (stable) f6c140a9126f - Linux - VE-29-MARS-2019 - VE-29-MARS-2019 13:59:59-GOHDR!$\$\$\$\f 0  ! NXT  ! NXI  ! PVT  ! PVI  ! NDT  -PDT ?@4 4 ! NOR  ! CGT $OHDR $\$\$\$\x!0 COO #NOM :OCHKY0NOED eOHDR!$\$\$\$\ ?@4 4 #  ! NBR  ! CGT Pp(R????????????N1 N2 N3 N4 N5 N6 N7 N8 M1 Left Right OCHK 1PFLMED_NO_PROFILE_INTERNAL ! CGT  ! CGS ROHDR!$\$\$\$\:   ! NBR  ! CGT KqOHDR $\$\$\$\x HE8 ! CGT  `7OCHKMAI [wOHDR $\$\$\$\x0 NOD8NOM i OHDR!$\$\$\$\   c  ! NBR  ! CGT XOCHK 1PFLMED_NO_PROFILE_INTERNAL ! GEO 4 ! CGT  ! CGS KiOHDR!$\$\$\$\:   ! NBR  ! CGT K{8]OHDR!$\$\$\$\     ! NBR  ! CGT XŁOCHKNUMenOHDR $\$\$\$\x meshE OHDR $\$\$\$\x NOEUDr FAMILLE_ZERO")-vaXOHDR $\$\$\$\" Left5RightwA'OHDR $\$\$\$\x  ! NUM GRO [cOHDR $\$\$\$\x NOM[ ! NBR  OHDR!$\$\$\$\:PP  P{UYOHDR $\$\$\$\x  ! NUM GRO  FOHDR $\$\$\$\x NOM ! NBR  KOHDR!$\$\$\$\:PP  PBmOHDR!$\$\$\$\   7  ! NBR  ! CGT X%/OCHKFAM nKOHDR $\$\$\$\"  ! NUM ={yFHDB$N ESP  DIM  TYP DESCREE PAR CODE_ASTERUNT SANS UNITES SRT  REP NOM1X Y Z UNI1INCONNUE INCONNUE INCONNUE  NXT  NXI OHDR $\$\$\$\xKC>  resu____DEPL'resu____EPSI_ELNO/resu____SIEF_ELNO9OCHKFASLCHA&&@OHDR!$\$\$\$\h" )] ! NCO  ! TYP  JNOM1DX DY DZ JUNI1 UNT MAImeshs6OHDR $\$\$\$\x6+0  ! NDT ) ֝OCHK;(0000000000000000000100000000000000000001 )H OCHK -PDT ?@4 4 ! NOR  ! RDT  ! ROR ȷOHDR $\$\$\$\x "MED_NO_PROFILE_INTERNALf++[upOCHKNOE*{OHDR $\$\$\$\xT,C  ! NBR  GAU!kOCHK 1PFLMED_NO_PROFILE_INTERNAL GAU/OCHK-/ ! NGA ;OHDR!$\$\$\$\ ?@4 4 .gLOCHK CO,r,~????????????OHDR!$\$\$\$\" 1] ! NCO  ! TYP  zNOMaEPXX EPYY EPZZ EPXY EPXZ EPYZ zUNIa UNT MAImesh¤kOHDR $\$\$\$\x34  ! NDT \2 +DOCHK;(0000000000000000000100000000000000000001l1H1OCHK -PDT ?@4 4 ! NOR  ! RDT  ! ROR ȷOHDR $\$\$\$\x "MED_NO_PROFILE_INTERNAL3^4[K3OCHKNOE.HE83FtoOHDR $\$\$\$\x4C  ! NBR  GAUWm`OCHK 1PFLMED_NO_PROFILE_INTERNAL GAU/OCHK6/ ! NGA 7xOHDR!$\$\$\$\00 ?@4 4 7ȟTOCHK CO4????????EaEa͞^&1<̞^&1<>&,t=mC  ! NBR  GAUfxOCHK 1PFLMED_NO_PROFILE_INTERNAL GAU/OCHK?/ ! NGA >IOHDR!$\$\$\$\00 ?@4 4 AOCHK CO|>XFn4r@Fn4r@Fn4r@Fn4r@Fn4r@Fn4r@Fn4r@Fn4r@3@8@,@=@9@0@8@.@B>ȟ@"B>ȟ@ B>ȟ@&B>ȟ@!B>ȟ@B>ȟ@$B>ȟ@B>ȟ@dffffʒ@jffffʒ@_ffffʒ@offffʒ@hffffʒ@bffffʒ@lffffʒ@`ffffʒ@t΁@t΁@t΁@t΁@t΁@t΁@t΁@t΁@rm&=?N0V4@1bjs(=2j=aE 8C=$=OHDR $\$\$\$\" D] ! NCO  ! TYP COCHKK>resu____ENEL_ELNOBqgOCHK *NOMTOTALE *UNI UNT MAImesh_rOHDR $\$\$\$\xXF4  ! NDT E VTOCHK;(0000000000000000000100000000000000000001-Do0 SE288C0 ! CGT TE4G^rOCHKMAI,8^˚uOHDR Ɣ\Ɣ\Ɣ\Ɣ\x=0 NOD9:FAMJ; .OHDR!Ɣ\Ɣ\Ɣ\Ɣ\""  0 ! NBR  ! CGT R OCHK 1PFLMED_NO_PROFILE_INTERNAL ! GEO f ! CGT  ! CGS TBOHDR!Ɣ\Ɣ\Ɣ\Ɣ\  81D ! NBR  ! CGT ROHDR!Ɣ\Ɣ\Ɣ\Ɣ\  |1D ! NBR  ! CGT R_OCHKNUMf<-WrOHDR Ɣ\Ɣ\Ɣ\Ɣ\xuB0 NODu>?FAM=@ OCHKT0TR3=G)cOHDR!Ɣ\Ɣ\Ɣ\Ɣ\   10 ! NBR  ! CGT R(ͩOCHK 1PFLMED_NO_PROFILE_INTERNAL ! GEO  ! CGT  ! CGS fOHDR!Ɣ\Ɣ\Ɣ\Ɣ\  1 ! NBR  ! CGT R,"OHDR!Ɣ\Ɣ\Ɣ\Ɣ\  2 ! NBR  ! CGT R?xOCHKNUMYAOHDR Ɣ\Ɣ\Ɣ\Ɣ\xhG0 NODhCDFAM0E 'SYOCHKQU4BrOHDR!Ɣ\Ɣ\Ɣ\Ɣ\HH  2  ! NBR  ! CGT R/OCHK 1PFLMED_NO_PROFILE_INTERNAL ! GEO  ! CGT  ! CGS ^`OHDR!Ɣ\Ɣ\Ɣ\Ɣ\  03H ! NBR  ! CGT R7OHDR!Ɣ\Ɣ\Ɣ\Ɣ\  x3H ! NBR  ! CGT RIOCHKNUMLFOHDR Ɣ\Ɣ\Ɣ\Ɣ\x+T0 NOD+HGIFAMI #lOHDR!Ɣ\Ɣ\Ɣ\Ɣ\  3 ! NBR ? ! CGT RYOCHK 1PFLMED_NO_PROFILE_INTERNAL ! GEO 0 ! CGT  ! CGS *OHDR!Ɣ\Ɣ\Ɣ\Ɣ\??  K ! NBR ? ! CGT R@x()*+-./02345789:<=>?ABCDFGHIKLMNPQRSUVWXZ[\]_`abdefgijklnopqstu        ,16;@EJOTY^chmrvwxOHDR!Ɣ\Ɣ\Ɣ\Ɣ\??   L ! NBR ? ! CGT R|POCHKNUMS~1OHDR Ɣ\Ɣ\Ɣ\Ɣ\xY0 NODU:VFAMV x[OCHKPY5[T)OHDR!Ɣ\Ɣ\Ɣ\Ɣ\ZZ  Mh ! NBR  ! CGT R I!&OCHK 1PFLMED_NO_PROFILE_INTERNAL ! GEO 1 ! CGT  ! CGS lOHDR!Ɣ\Ɣ\Ɣ\Ɣ\  7H ! NBR  ! CGT RH~OHDR!Ɣ\Ɣ\Ɣ\Ɣ\  oNH ! NBR  ! CGT ROCHKNUMX`+dFSSE+e6FHDBssi ESP  DIM  TYP DESUNT SRT  REP NOMUNI NXT  NXI tests/meshes/medit/000077500000000000000000000000001456244072500146175ustar00rootroot00000000000000tests/meshes/medit/cube86.mesh000066400000000000000000000064031456244072500165740ustar00rootroot00000000000000MeshVersionFormatted 1 Dimension 3 #Mesh generated by GAMBIT converted by GAMBIT_to_LifeV (Martin P.) Vertices 39 1 0 1 6 1 0 0 4 1 0 0.5 3 1 1 0 5 1 0.5 0 4 1 1 1 6 1 1 0.5 5 1 0.5 1 6 1 0.707565 0.707566 3 1 0.292433 0.292434 3 1 0.652965 0.347034 3 1 0.347033 0.652966 3 0 1 0 5 0.5 1 0 5 0 1 1 6 0 1 0.5 5 0.5 1 1 6 0.292435 1 0.707566 5 0.707567 1 0.292434 5 0.347035 1 0.347034 5 0.652967 1 0.652966 5 0 0 0 4 0 0.5 0 4 0 0 1 6 0 0 0.5 2 0 0.5 1 6 0 0.292435 0.707566 1 0 0.707567 0.292434 1 0 0.347035 0.347034 1 0 0.652967 0.652966 1 0.5 0 0 4 0.5 0 1 6 0.707565 0 0.707566 2 0.292433 0 0.292434 2 0.652965 0 0.347034 2 0.347033 0 0.652966 2 0.581989 0.58199 0 4 0.581989 0.41801 1 6 0.646741 0.569188 0.569188 0 Tetrahedra 86 32 1 33 38 1 32 36 38 33 1 12 33 1 38 1 12 33 3 1 1 12 1 8 38 1 27 32 36 38 1 27 36 32 24 1 27 32 38 26 1 35 3 12 33 1 35 10 12 3 1 30 26 27 38 1 27 25 36 24 1 27 24 32 26 1 18 26 30 38 1 27 36 25 29 1 17 8 9 6 1 2 35 3 10 1 2 35 10 31 1 35 31 37 10 1 37 5 11 10 1 17 6 9 21 1 15 18 26 30 1 17 26 18 38 1 34 25 36 29 1 35 31 34 37 1 23 34 37 29 1 23 34 29 22 1 23 37 28 29 1 23 34 31 37 1 34 25 29 22 1 17 15 18 26 1 15 18 30 16 1 6 9 21 7 1 37 4 19 11 1 37 11 5 4 1 31 37 10 5 1 2 5 31 10 1 37 14 19 4 1 7 19 4 11 1 20 37 14 19 1 20 28 14 37 1 20 28 30 16 1 20 30 18 16 1 23 14 28 37 1 23 31 34 22 1 13 23 14 28 1 20 28 16 13 1 20 13 14 28 1 39 37 19 11 1 39 11 9 12 1 39 20 19 37 1 39 20 21 19 1 39 19 7 11 1 39 19 21 7 1 39 20 18 21 1 39 18 20 30 1 39 38 18 30 1 39 9 11 7 1 39 21 9 7 1 39 17 9 21 1 39 38 12 8 1 39 12 9 8 1 39 12 38 33 1 39 33 35 12 1 39 10 37 11 1 39 35 37 10 1 39 11 12 10 1 39 12 35 10 1 39 38 36 33 1 39 35 33 36 1 39 38 17 18 1 39 21 18 17 1 39 29 30 28 1 39 30 20 28 1 39 28 37 29 1 39 20 37 28 1 39 36 27 29 1 39 29 27 30 1 39 27 36 38 1 39 38 30 27 1 39 37 34 29 1 39 35 34 37 1 39 29 34 36 1 39 35 36 34 1 39 8 17 38 1 39 9 17 8 1 Triangles 72 27 24 26 1 27 25 24 1 25 29 22 1 23 22 29 1 13 23 28 1 28 16 13 1 15 16 30 1 15 30 26 1 30 27 26 1 27 29 25 1 28 30 16 1 23 29 28 1 29 30 28 1 29 27 30 1 32 33 1 2 33 3 1 2 2 3 35 2 2 35 31 2 31 34 22 2 34 25 22 2 25 36 24 2 36 32 24 2 32 36 33 2 35 3 33 2 34 36 25 2 35 34 31 2 35 36 34 2 35 33 36 2 8 9 6 3 6 9 7 3 7 11 4 3 11 5 4 3 2 5 10 3 2 10 3 3 12 1 3 3 12 8 1 3 12 9 8 3 9 11 7 3 10 12 3 3 5 11 10 3 11 12 10 3 11 9 12 3 37 14 4 4 37 4 5 4 13 14 23 4 23 31 22 4 2 31 5 4 23 14 37 4 23 37 31 4 31 37 5 4 17 18 15 5 15 18 16 5 20 13 16 5 20 14 13 5 14 19 4 5 7 4 19 5 6 7 21 5 17 6 21 5 21 18 17 5 20 16 18 5 19 21 7 5 20 19 14 5 20 21 19 5 20 18 21 5 32 1 38 6 1 8 38 6 24 32 26 6 17 15 26 6 17 8 6 6 32 38 26 6 17 26 38 6 8 17 38 6 tests/meshes/medit/hch_strct.4.be.meshb000066400000000000000000000475241456244072500203630ustar00rootroot00000000000000!2??e,>&֟ի?>&֟ժ??e,?>&֟է??>&֟ժ?ffffff?;u|6LW$??ffffff|6LW#?ffffff?;?u|6LW ?ffffff?|6LW#?G9?1:ڮ!?G9ڮ!?G9?1;?ڮ!?G9?ڮ!?矎xd?1:ڮ!?矎xdڮ!?矎xd?1;?ڮ!?矎xd?ڮ!C?*3@¼li?iF1?_LvJOE࿤z?}BO&ݤjlj1 CQ?2  $AJ?o1#oaKV?Y٭c"eIVJhLUPhvGxd&\,8}^o:uWMlH`FA'Trc} g7-F3[7m>0p%~*/Hqw#2DR,*@gD"8 ͈XTq#@IsO5=c]4Tq#Mc]1Tq#@IsO7@=c]0?*3.?@˜?~?F??_LvJj?}BO?ݤ`?2 ?ڤU?o1!Ӳ?`?Y٫?c"e -hLV ?h0v&]E?,8냝:u?lֻ`m]?A]rcl?,FN@3[7l,*/Hs@#2@gDԂ@8 ͈Tq#@Mc]4?]`?fiLKa?F=?frJE:JI?AO?f8C>8WbU??g,jo6h?5\?hG++ZKG?.H?xfu` 2?zvI-?'9F R>?5m䡞?7ċ8? =?tv@W?_uכ?)nxhM@ ?]'!9@'T@ nKRnՓ@ g7-@)^@1p%~@,NnL# @DҪ,*@@t+8UY@Y @TYq"@IsO6=c]4@TYq"Mc]3@TYq"@IsO7@=c]1?fiM1?KaȘ?fr@?:U?f8Y?>7P?g,?o4'D?hH\?K ?xfy:?2Žq?+oP? ?7\?qi@?t|?@ /{?) ?xhLIm?_? LJ@ nKT>?n@*n@@,No@# @@tB@8U@TYq"@Mc]3?G9ܚnG͸?G9Vx?G98?G9Wx &?G9ZP?иl #ʇW?i c=-B?đ ȮSt?ʰ|Js t?-:8q(8pDNN(.&s]ga/֛h(Cq\ >f:܍@TJNG bh>f:܍W bg>f:܍@TJN@G be?G9?ܚnG͸?G9?Vx?G9?8?G9?Wx &?G9?ZP?иl #?ʇW?i ?c=-B?đ ?ȮSt?ʰ|J?s t?-:?8q(?8pDNN(@.@&s]ga@/֛h(@Cq\ >f:܍@W bg?矎xdܚnG͸?矎xdVx?矎xd8?矎xdWx &?矎xdZP?nqʇW?zc=-B?;ۑȮSt?S|Qs u?B-8q?P08-8pDO?ed'[@\yvL&s_@ga/֛h@*Cq\ @?f:܊@TJNG bi@?f:܊W bh@?f:܊@TJN@G bf?矎xd?ܚnG͸?矎xd?Vx?矎xd?8?矎xd?Wx &?矎xd?ZP?nq?ʇW?z?c=-B?;ۑ?ȮSt?S|Q?s u?B-?8q?P08-?8pDO?ed'[@@\yvL@&s_@ga@/֛h@*@Cq\ @?f:܊@W bh?*3?g2 ᅰ@½?i?mF??H16_LvJ?}BO&? ݤj?2 ?A@ ?o1#o?I"a?Y٭?b0W8!c"eIhLUP?F N"hvI&\?xXW1,8:uWN?Ѱ)&l`F?3i7Arc}?M،˿F@ o)}3[7m@*/Hqu@!py2@gD"@4р{n( ͈?*3?g2 ?@¸?i?m?F??H16?_LvJ?}BO&? ?ݤj?2 ?AB??o1#o?I$?a?Y٭?b0W8#?c"eIhLUP?F N"?hvD&\?xXW1?,8:uWN?Ѱ)'?l`F?3i7?A~rc}?M،?F@ o)}@3[7m=*/Hqu@!pz@2@gD"@4р{n@( ͈?fiL?RݛyuKa?frJE?Ou:JK?f8C?!1rIv>8WbW?g,j?KZ'wo6j?hG++Z?-R-|KG?xfu` ?a L2?'9F?Uܿ R>?7ċ?ؓ[8?tv?&sM@X?)n?ׇ.xhM?]'?!9@ nKR?6(ZnՔ@)^@ ܽ.-@,NnJ@!O{ @@t+@4zũx(U[?fiL?Rݛy?uKa?frJE?O?u:JF?f8C?!1rI?v>8WbR?g,j?KZ'?wo6e?hG++Z?-R-?|KG?xfu` ?a L?2?'9F?U? R<?7ċ?ؓ\?8?tv?&sM?@W?)n?ׇ1?xhM?]'??!9@ nKR?6([?nՑ@)^@ ܽ.-@@,NnL@!O}@@@t+@4zũy@(UX?G9?k>X8ܚnGͺ?G9?pRvпVz?G9?:af8:?G9?G9|,Wx (?G9?dbĿZP?иl #?Э髿ʇX?i ?c 󊣿c=-B?đ ?K꿰ȮSt?ʰ|J?^v(s v?-:?۪ T8q(? g8pDON(@t.@/9p &s_ga@+s}Z֛h(@@օY3q\ ?G9?k>X9?ܚnGʹ?G9?pRv?Vt?G9?:af9?4?G9?G9|-?Wx "?G9?db?ZP?иl #?Э?ʇU?i ?c ?c=-B?đ ?K?ȮSr?ʰ|K?^v(?s p?-:?۪ V?8q(? g ?8pDLN(@t?.@/9r@ &s[ga@+s}]@֛h(@@օY@3q\ ?矎xd?k>X8ܚnGͺ?矎xd?pRvпVz?矎xd?:af8:?矎xd?G9|,Wx (?矎xd?dbĿZP?nq?Э髿ʇX?z?c 󊤿c=-B?;ۑ?K꿰ȮSt?S|Q?^v(s v?B-?۪ T8q?P08,? g8pDO?ed'[@t@\yvL@/9p &s`@ga@+s}[֛h@*@@օY3q\ ?矎xd?k>X9?ܚnGʹ?矎xd?pRv?Vt?矎xd?:af9?4?矎xd?G9|-?Wx "?矎xd?db?ZP?nq?Э?ʇU?z?c ?c=-B?;ۑ?K?ȮSr?S|Q?^v(?s r?B-?۪ X?8q?P08-? g!?8pDN?ed'[@t?@\yvL@/9s@ &s]@ga@+s}^@֛h@*@@օY@3q\ "p    3212414D1decfdcvfc0h        2342D4eddffv  "!!"$##$&%%&(''(*))*,++,.--.0//031 wwxxyyzz{{||}  }~""~$$&&((**,,..003 wwxxyyzz{{||}}~~FFHHJJLLNNPPRRTTVVXXZZ\\^^``bbeEFFEGHHGIJJIKLLKMNNMOPPOQRRQSTTSUVVUWXXWYZZY[\\[]^^]_``_abbace565768798:9;:!<;!#=<#%>=%'?>')@?)+A@+-BA-/CB/1DC5566778899::;;<<==>>??@@AABBCCDg hgihjikjlkmlnmonpoqprqsrtsutvu gEghGEhiIGijKIjkMKklOMlmQOmnSQnoUSopWUpqYWqr[Yrs][st_]tua_uvca :`  !"!"#$#$%&%&'('()*)*+,+,-.-./0/0123!!##%%''))++--//1425566778899::;;!<!<#=#=%>%>'?'?)@)@+A+A-B-B/C/C1D4EFEFGHGHIJIJKLKLMNMNOPOPQRQRSTSTUVUVWXWXYZYZ[\[\]^]^_`_`ababdce EEGGIIKKMMOOQQSSUUWWYY[[]]__aafcd  gEgEhGhGiIiIjKjKkMkMlOlOmQmQnSnSoUoUpWpWqYqYr[r[s]s]t_t_uauavcf OH wwxxyyzz{{|| } }"~"~$$&&((**,,..0032           24 5566778 8 9 9 : : ; ; < < ==>>??@@AABBCC4D wwxxyyzz{{||}}~~  !!""## $$%%&& ' ' ( ( ) ) * * + +,,--../ / 0!0!1"1"2#2# $$%%&& ' ' ( ( ) ) * * + +,,--..//001122FFHHJJLLNNPPRRTTVVXXZZ \ \!^!^"`"`#b#bde $$%%&&''(())**++,,--.. / /!0!0"1"1#2#2fd $g$g%h%h&i&i'j'j(k(k)l)l*m*m+n+n,o,o-p-p.q.q/r/r0s0s1t1t2u2uvf6tests/meshes/medit/hch_strct.4.meshb000066400000000000000000000474701456244072500177760ustar00rootroot00000000000000!2?,ٓe?՟&>?՟&>?,ٓe?՟&>??՟&>?ffffff?;?$WL6|u?ffffff?#WL6|ffffff?;? WL6|u?ffffff?#WL6|?9G?:1ک?!ڝ9G?!ڭ9G?;1ک?!ڝ?9G?!ڭ?dx?:1ک?!ڝdx?!ڭdx?;1ک?!ڝ?dx?!ڭ?Cš3*?̾@ili?F1㑩?JvL_zEO&OB}?jQC 1jl 2?JA$ o#1o˧?aħVKѭY?Ie"cJVPULhGvhdxǿ\&зȧ8,Ŀo^}ݿMWu:ԿlԿHF`AT'}cr-7g F>m7[3~%p0wqH/*2#*,RD"Dg@ˆ͋ 8X#qT5OsI@4]c=#qT1]cM#qT7OsI@0]c=@.3*?̾@?~?F?㑩?jJvL_?OB}?`? 2?U?!1o˧?`ħ?寫Y?- e"c? VLhv0h?E]&з8,?u:Կλl?]m`]A?lcr,?NF,l7[3@sH/*2#@Dg@͋ 8@#qT4]cM@`͉]?Lif?aK=F?EJrf?IJ:ܭOA?C8f?UbW8>ܽ?j,g?h6o\5?Z++Gh?GݙKH.? `ufx?2-Ivz?F9'?>R m5?7?8= ?vt?W@Ûu_?n)?Mhxҿ @']?9!T'@RKn @n-7g @^)@~%p1@LnN,@ ؤ#*,D@+Ψt@@YU8 Y@"qYT@6OsI@4]c="qYT@3]cM"qYT@7OsI@1]c=@1Mif?ؘaK?@rf?U:?Y8f?P7>?,g?D'4o?\Hh? K?:yfx?q¢2?Po+? ?\7?@iq?|t?{/ @? )?mILhx?_? ?>TKn @ٍn?n*@@oN,@ ؤ#@Bڨt@@U8@"qYT@3]cM@9G?Gnܭ9G?xV㭿9G?89G?& xW9G?ɵPZ# l?Wʱ i?B-=c ?tSJ|?t sο:-п?q8߿Ԃ(NDp8(N.]s&aʑgفh/( \qC:f>NJT@hb G:f>gb W:f>NJT@eb G@9G?Gnܭ?9G?xV?9G?8?9G?& xW?9G?ɵPZ?# l?Wʱ? i?B-=c? ?tS?J|?t s?:-п?q8?Ԃ(NDp8?(N@.]s&@aʑgفh/@( \qC@:f>gb W@dx?Gnܭdx?xV㭿dx?8dx?& xWdx?ɵPZqnɣ?Wʱz?B-=c;?tSQ|S?u sο-B?q8߿-80P?ODp8['de?Lvy\@_s&aʑg@ہh/*@ \qC:f?@NJT@ib G:f?@hb W:f?@NJT@fb G@dx?Gnܭ?dx?xV?dx?8?dx?& xW?dx?ɵPZ?qnɣ?Wʱ?z?B-=c?;?tS?Q|S?u s?-B?q8?-80P?ODp8?['de?@Lvy\@_s&@aʑg@ہh/@*@ \qC@:f?@hb W@3*? 2g?̾@i?m?F㑩?61H?JvL_&OB}? Ϣ?j 2?@A? o#1o˧?"I?aħѭY?!8W0b?Ie"cPULh"N F?Ivh\&з1WXx?ʧ8,NWu:Կ&ĺ)?lĿF`뿾7i3?Aֿ}crˌM?F})o @@m7[3uqH/*yp!@2"Dg@n{4@Ĉ͋ (3*? 2g?̾@?i?m?F?㑩?61H?JvL_?&OB}? Ϣ?j? 2?BA??o#1o˧?$I?aħ?ѭY?#8W0b?Ie"c?PULh"N F?Dvh?\&з1WXx?Ƨ8,?NWu:Կ'ĺ)?l?F`7i3?~A?}crˌM??F})o @=m7[3@uqH/*zp!@2@"Dg@n{4@͋ (@Lif?yݫR?aKuEJrf?ʆO?KJ:uC8f?Ir1!?WbW8>vj,g?'ZK?j6owZ++Gh?-R-?GݙK| `ufx?L a֤?2F9'?U?>R 7?[?8vt?Ms&?X@n)?.?Mhx¿']??9!տRKn @Z(6?n^)@-. @JnN,@{O!@ ؤ+Ψt@@xz4@[U(Lif?yݫR?aKu?EJrf?ʆO?FJ:u?C8f?Ir1!?RbW8>v?j,g?'ZK?e6ow?Z++Gh?-R-?GݙK|? `ufx?L a֤?2?F9'?U?kܩ?Gnܝ9G?vRp?zV㝿9G?8fa:?:9G?,|9G?( xW9G?bd?˵PZ# l?Ю?Xʡ i? c?B-=c ?K?tSȰJ|?(v^?v s:-п?T Ѫ?q8Ͽ؂(g ?ODp8(Ntۯ@.p9/@_s& aʑgZ}s+@܁h(Y@@ \q39G?9X>kܩ?Gnܝ?9G?vRp?tV?9G?9fa:?4?9G?-|9G?" xW?9G?bd?ŵPZ?# l?Ю?Uʡ? i? c?B-=c? ?K?rSȰ?K|?(v^?p s?:-п?V Ѫ?q8?Ԃ( g ?LDp8?(Ntۯ@?.r9/@[s& @aʑg]}s+@ׁh@(Y@@ \q3@dx?8X>kܩ?Gnܝdx?vRp?zV㝿dx?8fa:?:dx?,|9G?( xWdx?bd?˵PZqnɣ?Ю?Xʡz? c?B-=c;?K?tSȰQ|S?(v^?v s-B?T Ѫ?q8Ͽ,80P?g ?ODp8['de?tۯ@Lvy\@p9/@`s& aʑg@[}s+@݁h*@Y@@ \q3dx?9X>kܩ?Gnܝ?dx?vRp?tV?dx?9fa:?4?dx?-|9G?" xW?dx?bd?ŵPZ?qnɣ?Ю?Uʡ?z? c?B-=c?;?K?rSȰ?Q|S?(v^?r s?-B?X Ѫ?q8?-80P?!g ?NDp8?['de?tۯ@?Lvy\@s9/@]s& @aʑg@^}s+@فh@*@Y@@ \q3@d"    3212414D1decfdcvfcX0        2342D4eddffv  "!!"$##$&%%&(''(*))*,++,.--.0//031 wwxxyyzz{{||}  }~""~$$&&((**,,..003 wwxxyyzz{{||}}~~FFHHJJLLNNPPRRTTVVXXZZ\\^^``bbeEFFEGHHGIJJIKLLKMNNMOPPOQRRQSTTSUVVUWXXWYZZY[\\[]^^]_``_abbace565768798:9;:!<;!#=<#%>=%'?>')@?)+A@+-BA-/CB/1DC5566778899::;;<<==>>??@@AABBCCDg hgihjikjlkmlnmonpoqprqsrtsutvu gEghGEhiIGijKIjkMKklOMlmQOmnSQnoUSopWUpqYWqr[Yrs][st_]tua_uvca :`  !"!"#$#$%&%&'('()*)*+,+,-.-./0/0123!!##%%''))++--//1425566778899::;;!<!<#=#=%>%>'?'?)@)@+A+A-B-B/C/C1D4EFEFGHGHIJIJKLKLMNMNOPOPQRQRSTSTUVUVWXWXYZYZ[\[\]^]^_`_`ababdce EEGGIIKKMMOOQQSSUUWWYY[[]]__aafcd  gEgEhGhGiIiIjKjKkMkMlOlOmQmQnSnSoUoUpWpWqYqYr[r[s]s]t_t_uauavcf 0O wwxxyyzz{{|| } }"~"~$$&&((**,,..0032           24 5566778 8 9 9 : : ; ; < < ==>>??@@AABBCC4D wwxxyyzz{{||}}~~  !!""## $$%%&& ' ' ( ( ) ) * * + +,,--../ / 0!0!1"1"2#2# $$%%&& ' ' ( ( ) ) * * + +,,--..//001122FFHHJJLLNNPPRRTTVVXXZZ \ \!^!^"`"`#b#bde $$%%&&''(())**++,,--.. / /!0!0"1"1#2#2fd $g$g%h%h&i&i'j'j(k(k)l)l*m*m+n+n,o,o-p-p.q.q/r/r0s0s1t1t2u2uvf6tests/meshes/medit/sphere_mixed.1.meshb000066400000000000000000013255641456244072500204720ustar00rootroot00000000000000e @ Nn<uy޿M&`?.+' ?uy޿R&`?_1<~/'ڿe?7?#07 ۿ{ź ?rz4g#.?~/'ڿe?ޛ<IDkԿ ?}:mV?ɽֿEױ?u6]?ʽֿ]^\6?+?IDkԿ ?j7Wʡ<즇cxɿpaQ[?1^tl?DOVϿn?iD܊?F^пFi?_X?DOVϿH_&?KpE?cxɿpaQ[?7=<l%ﳿ,7?Y _?Tl#7 &u?H4n?}<@D|?Ë\H?}<@Dڣ B0WL?Y4տ޺9YS|?pEaaٿʓ?LXzۿuy޿S&`.+' #07 ۿv~d#9u?nV"޿~<@D? 9uoV"޿Ul#7 ?Ij FĿl\( oݿl%?-7ϿX _ۿuy?V&`¿خɊ#07 ?}ź ˿uz4g#. ~/'?eѿAgvjmȽ?Fױпu6]Ϳɽ?\^\6տ+IDk? ؿ{H+=DOV?nӿiD܊ԿF^?Ei׿aX˿DOV?H_&ۿPpE릇cx?paQ[ݿ{QqگSl#7 ?&uԿH4n׿|<@D?|ؿË\Hҿ|<@D?٣ B<ܿaՠȿSl#7 ?KZ޿ l%?27߿tuy?[&`.+' ?#07 ?ź ˿cz4g#.?~/'?e7?ɽ?_^\6տo+?Ƚ?Kױпu6]?HDk? ȿy:mV?DOV?H_&ۿ/pE?G^?Ii׿QX?DOV?nӿiD܊?ꦇcx?paQ[Ϳ,^tl?Ul#7 ?KZ޿ ?<@D?ݣ B<ܿQՠ?~<@D?|ؿ\H?Tl#7 ?&uԿH4n?l%??7ϿT _?#07 ?CMskz4g#.?ʽ?jhܰ5p9?ʽ?Fhܰ?6p9?DOV?2}k2~ǎ?G^?NAGZX?EOV?}k2~?ʎ?Tl#7 ?Ij FĿi\( o?}<@D?a9umV"?}<@D?8u?oV"?Xl#7 ?Ij F?m\( o?A N֎<xyO&`?.+' ?xyT&`?_1<~/'e?7?#07 ~ź ?uz4g#.?~/'e?޻<KDk ?:mV?̽Gױ?u6]?̽`^\6?+?KDk ?l7W<cx鿄paQ[?3^tl?GOVn?iD܊?I^Ii?bX?FOVH_&?NpE?驪cx鿊paQ[?8=<l%ӿ07?[ _?Wl#7 ޿&u?H4n?~<@Dῶ|?ŋ\H?~<@Dݣ B0WL?Y4?&oTjso?G[&?mķ޿X 1?lށ0?k3<߿kK?EE/}[?߿N:?l ?vm0ge~䌻ӳ?*H+?9ujDæ?u yv?P}⿅ǻ?\? 9i俕?//ɂ?&+7ܗd?_BQ?ݽa[wl1?: ?ᅨ4=0.?YntY?c`xI&R?"2?(׼ |'?,3:-?N޿>o?="[ <mķ޿] 1?,;<k3<߿pK?E <߿N:?꠫J5<vm0ge࿃䌻?Qp<9ujDæ?xBn<P}⿌ǻ?< 9i保?SN<&+7d?&ؔ<ݽf[wl1?;"L <￑4=0.?z<c`xI-R?dP<(׼ ǝ|'?,5<:@ڿh.w?߁?@ڿi|?(d?.P@+ۿ ?/O?Յ èۿig?B+#?UkܿytT?}oo?[qZ ޿JB_u?7UN?@ YD?r?9b?1$?81KuY?>,F?QJ翟wd?$*_@?[cX [?P?bR?OEU?0g8N?R?-C ܿUkJ%?K#+I?/$4ܿMA?#;mx?Aվܿ!s ?cJE@̿?P&fݿ%b?ɡ/?1ݿN?a/޲?ҰǷȁ߿Mjغq?}G? &Ὶ}l?6B"?ke #`4?V]V?IL}.\{hw?ȵ?onEܷۛ?B?쿠Qo?Y]n +%?q,)rO?ֶ ? -1?tx?:@ڿm.w?p<@ڿi|??!<.P@+ۿ?Fl<Յ èۿig?{wp<Ukܿ~tT?\ik֝<[qZ ޿OB_u?yBl<@ YD?lG&<9b?f/ʢ<81$KuY?r]Mg <QJ翦wd?Θ#^<[cX [?8ܬ<bR?(bИ<0g8N?Oߵ<J}Կi?3!eC?@3տa ? &?Ul),տY`?"L?b!׿?./?ٿd<=?ZWc0?O/ۿGf ?s?r߅޿X٬?_1V,?V ;IN?c?J%e2?6쨊?w+D}JUŜ?I ??a>pU?@ʮ?mfɆ̴ֿn?t1ɫv?FOD׿LwW(?m?P+W>׿/U?h ?=ܺ:׿=p?bt|?L~fؿ12?go?h#aٿ]PK0L*?F{?a,&ۿw?oN{?G޿RV?v?@F;|O?_ ؼ+B?Voa㿶 Mq?8[? +*?F4{h?ٳBt/h?>pK}?H-@la?4 ?mfɆֿwII? ;?GOD׿g Пi?/̽?P+W>׿wy?{R3?>ܺ:׿fj?fG?M~fؿPEv ?a˚?h#aٿW ?OqU?b,&ۿ ?I0eq5?G޿;??@F=-[?2u`?VoaWˈF?-v? +CB?F3?ٳ+bS??qө?H- 7?XuY2+?J}Կi?9h\ڡ<W Կ7pQ?-{<ۡ[ԿUgj?=:)%<@3տa ?)" x<Ul),տY`?KZ <b!׿?mZp<ٿl<=?֥<O/ۿKf ?D<r߅޿X٬?|j^n<V ;IN?t<<J%j2?#n"m<w+D}PUŜ?Z!h<?a>pU?vtڂ<!xɿ5t?l?)Jɿ"?N??3qɿ{/?`?qʿbj(|z?AC&e?6G\D˿iǢm?BS7?-ma̿?H?&HjCϿ*R? 4?+ѿ?|#?uNӿm @?QNE?z1vDֿij?!e:?]H`ڿœn!f?jP/T?Wu 6 ^|?b1a?nB ?T-?BGqϿУr?-돣?(ϿGP?U$k5?r;IϿ6#?!k?V5Dп,?Je?&?N@>?j[UEä ?`+?N迗y7;?Ġtg?!xɿ 5t?>BK幢<)Jɿ"?~ˡW֢<4qɿ/?89Z<qʿjj(|z?f G`<6G\D˿qǢm?J<.ma̿?CÜ <&HjCϿ.R?JEb<+ѿ?P#*<uNӿm @? \,K<|1vDֿij?tO1Q<_H`ڿɜn!f?hqS<Xu 6 ^|?>_<nB ?U0K<ǧ8Nm? ̡w?P!Hh4?hr[?iNTӢ'(??83@~h?Yѭk?ȷ3W4̈́?n oiN?.z(B??u>)x\ZL+Bf?ە?rếgkO?St?=jn9ր0?|{4?n-ʿf'] ??Q1οt?o?I-?LѿZL? ^:?us儾տF@^)w?9?i8SaT??̀?\m_??#Λ p?程=*?zS'BOruP?gb4_~?xG*|¿aR:?^(j? (wÿ`ĵw?b1?f1ſo%T?r I?ؔHǿ` ?p-@Ң?4@¹>-ʿ#g?v6_x?Q1οk9?J?Lѿg=?rLg?us儾տ'Z?axF?ۿ`(?Ý]?L0D&TAП??YTOV?s[J<=?[ӕX ?lr}?^$2Ɲy?*&?S3YV?K?$F e4?d>R?np¿ay;?̨9z?+MAĿ݅l?̣0?Ecƿc"?xr$4?mv]Eʿ3G?ݨ?$ao@Ͽ^o튛? *?1 < }ҿ>7?JVE>?{2׿b)V?&6?ʧ8Tm?Y^<S!Hh4?Uꯒӡ<lNT֢'(?Z<;3@~h?HCV<̷3W4̈́?cc<.z(B?fc<u>)xaZL+Bf?fV<rếlkO?>bSЧ<=jn9ր0?t۠>ƪ<n?&g|<? ?$,?<5Ғ?B.GE?\<ͪiA?ӄ?|<:{T?:?)Oы<̼2Ց?v^?{%tw?5m ?ѻF?2۬UJ[<`+0?^ g?Dʒ[<p?ugK?j: +\g?$ei  ?E0W< ??)-Z?ܰp?~$fPr[!-i? ?#N]4ٟ?^p? |i`sWl*xu?5a?Ltb6??,վHeڿD?C?a5iDxVm?^,Ga?Y-n?6<U?,s^h?$X?㛡>fwQ? Ͱ?e4]wd(?SʭB.?Kwڭ:-?w?\6x^w?nb?hxfW?J?frKzg1AR?Q;ւ?v|U^fx?:9?2ClrUzjYc?5cˉ?4GϭVK ?apc?A#d*1ļ?PԍH?W,'+(_m?8٭W?)^ӏ?w?[oeM5]?4+I?!aNm%- ?SXY:<1!rKlB&?0S'S<DUHG"Q?wc W~<ngĹ'_?ʷʠ<>]s񺄼VQ!? )1}P<=6ԅ"ei  ?;<Hć?&,c`ڣ<E5Ғ?\@ߖΥ<0[ҪiA?7%<߄<G@{T??G</Q ϼ2Ց?z<lbI .&?xLf^<Td(?7&6$b<N޿>o?G[&mķ޿` 1?iށ0k3<߿sK?BE/}[߿N:?l vm0ge࿇䌻ӳ?*H+9ujD!æ?r yv¿P}⿐ǻ?\ÿ 9i俢?+/ɂſ&+7d?ZBQȿݽi[wl1?: ̿ᅰ4=0.?VntYпc`xI2R?"2Կ)׼ Ν|'?(3:-ٿ-C ܿXkJ%?J#+I.$4ܿMA?;mxAվܿ$s ?cJE@̿O&fݿ(b?ɡ/1ݿQ?[/޲ѰǷȁ߿Mjغq?vG &῜}l?.B"ÿke #`4?M]VſHL}._{hw?ȵǿonHܷۛ?B˿쿣Qo?S]n +%пp,*rO?ֶ ӿ •-1?txؿ:@ڿp.w?܁ο@ڿi|?%dο.P@+ۿ?,OϿՅ èۿig?B+#ϿUkܿtT?{ooп[qZ ޿SB_u?5UNѿ@ YD?rҿ9b?/$Կ81*KuY?;,F׿QJ翭wd?!*_@ڿ[cX [?P߿bR?OEU0g8N?PmfɆֿwII? ;FOD׿h Пi?̽P+W>׿wy?jR3=ܺ:׿fj?|fGL~fؿPEv ?a˚h#aٿW ?FqUa,&ۿ ??0eq5¿G޿;?ÿ@F=-[?2u`ƿVoaXˈF?-vɿ +CB?63οٳ,bS??qөҿH- 7?LuY2+׿mfɆֿ"̴n?o1ɫvͿGOD׿LwW(?mͿP+W>׿/U?c Ϳ>ܺ:׿=p?bt|οM~fؿ 12?boϿh#aٿbPK0L*?}F{пb,&ۿw?lN{ҿG޿WV?sӿ@FA|O?\ ؼ+BֿVoa㿽 Mq?8[ٿ +*?A4{h޿ٳGt/h?;pK}H-Fla?4 J}Կi?0pU?@ʮCGqϿ=`Bs%?z^r])Ͽ3~N? Ħs;IϿxX?tϻV5Dпؠ+?tm5P&?N@>̿j[UEä ?T+ѿN还y7;?tgտ_пT~?gNup˿пq?VK˿k:пWp'?L=˿@ѿo硖?.\jd̿l&%ѿakZ?FͿ:ҿ0?(c"οWĂeԿRnp¿ay;?9z+MAĿޅl?̣0Fcƿc"?lr$4¿ov]Eʿ4G?ݨĿ&ao@Ͽ^o튛?*ȿ2 < }ҿ>7?JVE>ο{2׿c)V?&6ҿi8SaT? ?̀ȿ\m_?ȿ#Λ p?ܨ=*ɿzS'COruP?\b4_~ɿyG*|¿aR:?S(jʿ (wÿaĵw?b1˿f1ſo%T?r IοܔHǿ` ?i-@Ңп8@¹>-ʿ#g?o6_xҿQ1οl9?JտLѿg=?rLgٿys儾տ'Z?axF߿ۿ`(?Ý]i8S%?~0/]nXҿ\mN?榤Ltҿ#ΛUJK?gAKҿzS'Od3$?wR"nҿzG*|¿j?/Fݒӿ (wÿn.?ݚԿf1ſMq?~'qֿܔHǿK?M9 ؿ8@¹>-ʿi'] ?ۿQ1οt?o?B-߿Lѿ^L? ^:ys儾տJ@^)w?~9L0D&flft?E1xf׿YTqY*?R׿[ӕŨw?2׿"^$2Ab=? : GSؿ@o Q?a eWٿ$F)#\=?=jڿnp¿@;?ȽRܿ+MAĿ9j@?LE}߿Fcƿ+[A?Rvov]Eʿ(5`?Rgr,|&ao@Ͽs30?PXߤC2 < }ҿ6ǥ+?{2׿ k?\'Zcʧ8Xm? ̡wۿS!Hh4?hr[ۿlNTآ'(?ۿ;3@~h?Yѭk̷ܿ3W4̈́?i oiNݿ.z(B?޿u>)xdZL+Bf?ڕrếokO?St=jn9ր0?y{4n-=?Iſ?Q)Ix>?ҰpſR!-i? ƿty%UT4ٟ?^pȿVz UVtWl*xu?5a˿LyY7?οƙ>>\ڿD?;ѿ?pϞ'aDxVm?U,GaտB`LSd?+<Uٿoi.j_h?$X߿2?'-rn?#- п_ RrY?KlB&п럎sC?EG"Qп\d[s9@?'_пs?SQ!ѿ>OuW>?ei  ҿsJXv ?ӿ #yB.GE?5ҒտNe3 D|ӄ?ΪiAؿ]M:?<{Tۿc2Nv^?ͼ2ՑN2`z'+s?F .&\CB}п?(|=> ?ѻFտqb+0?^ gտ€ۆp?ugKտڅD|ZF?_`ֿ$"nU)13eJt?;twٿ])˳gdЕ?B1Lٿ8 ?'JPٿ,><;?TrYڿ)u~5?6,ۿQ-Ͼ?~A8<ܿΣ`w'[?%t'߿%0왼 ^F?$%烝v?GJ=ϠTb ?0_裼w.? Hl-  6?v3uP=-:8͖?^ag缑(- ?kۿmבKlB&?Yۿ!18KG"Q?CܿLBQZǹ'_?6@ܿlz쒼YQ!?ݿ9W%ei  ?W>߿o@沕? #C ֗5Ғ?@.GE̚תiA?ЄJ鞼F{T?:[NҼ2Ց?r^"(CM .&?'+sMn(?B}пN޿>oG[&mķ޿^ 1lށ0k3<߿qK㲿EE/}[߿N:l vm0ge࿄䌻ӳ*H+9ujDæᴿu yv¿P}⿍ǻ\ÿ 9i俞//ɂſ&+7d_BQȿݽg[wl1: ̿ᅭ4=0.ÿYntYпc`xI.Rǿ"2Կ(׼ ȝ|'Ϳ,3:-ٿ-C ܿtQ5,F׿QJ翢wdο$*_@ڿ[cX [ҿP߿bRֿOEU0g8NۿRmfɆֿCl?0[#ֿGOD׿JL~ ?&żDֿP+W>׿4IKP2?nֿ>ܺ:׿ `?(0ֿM~fؿLk ?o㇞׿h#aٿ=.?#4ؿb,&ۿWQ?檆ۿG޿܊?kmݿ@Fwk?QACVoaޣ*o|?ҧ4J +翓#dv?0Dٳ쿢{?׿%IKP2nֿ>ܺ:׿`(0ֿM~fؿLk p㇞׿h#aٿ-.$4ؿb,&ۿWQ檆ۿG޿܊kmݿ@FwkQACVoaţ*o|ҧ4J +翄#dv0Dٳ쿐{?<ſ)H-Uewʿ찖PJ}Կiȿ2pU㿒@ʮDGqϿ]=zJ? ',ڿ*ϿºǾ?Zۿt;IϿ?_ۿV5DпX5{?rۿ&!Q8Z-ʿtд?oK16Q1οSYS?";Lѿ,=:p? N={s儾տ.yyJ?uZGۿe(?9i8S\| Pxî޿\m2((g[޿#Λ .- j:߿zS'GlQ߿{G*|¿e/ &d (wÿOCf1ſmڰuߚ ޔHǿPu[c:@¹>-ʿOдoK16Q1οSYS#;Lѿ=:p N=zs儾տ.yyJvZGۿe(ſ9L0D&ۅ!0ĿZݿYTXcOĿ0Llݿ[ӕ^OĿK޿"^$2`.Ŀ w޿ŊſEӿ߿$F-Nqǯƿ$np¿ ȿްl+MAĿJ%!˿Fcƿ7K ο`Oov]Eʿ}̗ѿݩ&ao@ϿgXFԿ\Q{2 < }ҿEmWٿ%3c{2׿f߿֑ɧ8OmϿ ̡wۿR!Hh4Ͽhr[ۿkNTӢ'(пۿ:3@~hпYѭkܿ˷3W4̈́пm oiNݿ.z(Bѿ޿u>)x\ZL+BfӿەrếgkOտSt=jn9ր0׿{{4nbM>^xNW4?5E#-2â>@X?i fW?UP? jcCKcn?2<NL] ?k]| cWB 8?KîjE} @K<<%- Aᥙof#YD?h<"ei  +EIH|,< 2Csy޲<5Ғ›nk^6<ҪiAǽ:dyw<@{T xY :.m<ϼ2Ց'B=]x>~_iNW45E#L-G>@Xÿi"eO>UPƿ jClإKcnʿ2< }ɜԥN пm]|KR5 8ԿMîj#0j;kȿstݿwF/ָȿI!ݿMȿS'zS'޿T`\hɿli޿S ‼&M3ʿBTI߿ȁVH˿*x Gv\x0 ο$%9KD8CwпtNRA釼2 ҿATiz1C]eտZÂUODXٿLn,.ݓV޿ד&ħ+˜347c4;"k"- пnۿ''KlB&пYۿJ1NDG"QпCܿ߿Z k]ӿ 0ׄ1p5ҒտB.GEC@ َͪiAؿӄr(mʑ:{Tۿ:+]̼2Ցv^ZmF .&俽'+s0🼛(B}пN޿>o¿)U,_mķ޿a 1¿Ղk3<߿tK¿&3߿N:ÿvm0ge࿈䌻ÿj;z͆9ujD"æĿR۠P}⿑ǻƿc%$ 9i俢ȿ+9!&+7d̿E=%ݽi[wl1пHxEXᅰ4=0.ӿO[c`xI2R׿_ζҚ(׼ Ν|'ݿxqU-C ܿXkJ%˿K#+I.$4ܿMA˿";mxAվܿ$s ˿cJE@̿O&fݿ(b̿ɡ/1ݿQ̿`/޲ѰǷȁ߿Mjغqο|G &῜}lп5B"ÿke #`4ҿT]VſHL}._{hwԿȵǿonHܷۛ׿B˿쿣QoۿX]n +%пp,*rOΎֶ ӿ •-1忥txؿ9@ڿn.wѿ܏@ڿi|ѿ隼-P@+ۿҿ 3 1Յ èۿigҿZUkܿtTҿ[qZ ޿PB_uӿ`@ YDտ,g ,]9b׿M 81'KuYڿ6/6QJ翪wd޿>m O[cX [j7ޜbR8nɰ0g8Nӻ촼mfɆ̴ֿnѿt1ɫvͿFOD׿LwW(ѿmͿP+W>׿/Uѿh Ϳ=ܺ:׿=pѿbt|οL~fؿ12ҿgoϿh#aٿ^PK0L*ӿF{пa,&ۿwԿoN{ҿG޿SVֿvӿ@F<|Oٿ_ ؼ+BֿVoa㿸 Mqݿ8[ٿ +*F4{h޿ٳCt/h>pK}H-Ala꿘4 mfɆֿwIIտ ;FOD׿g Пiտ/̽P+W>׿wyտ{R3=ܺ:׿fjֿfGL~fؿPEv ֿa˚h#aٿW ׿OqUa,&ۿ ڿI0eq5¿G޿;ܿÿ@F=-[2u`ƿVoaWˈF⿟-vɿ +CBF3οٳ+bS?꿾qөҿH- 7XuY2+׿J}Կiؿ(mW Կ7pQؿrȏx0ۡ[ԿUgjٿϧ@3տa ٿmhA=Ul),տY`ڿja&b!׿ۿ}$Sٿl<=޿FBਬO/ۿKf G={r߅޿X٬EﲱV ;IN忒= jJ%j24-.w+D}PUŜYjg?a>pU+9S¼CGqϿУrӿ-돣Կ)ϿGPӿU$k5Կs;IϿ6#ӿ!kԿV5Dп,ԿJeԿ&N@>̿j[UEä a+ѿN迗y7;Štgտ!xɿ 5tݿ PW)Jɿ"ݿpWlh2qɿ/ݿ[9 viqʿjj(|z޿g`쬼6G\D˿qǢm߿ xӭ,ma̿LYs&i&HjCϿ.R297/+ѿhDRȲuNӿm @d3Py1vDֿij-/&C[\H`ڿɜn!f'cnڼVu 6 ^|]y8܊nB @+hżL0D&blftԿH1xf׿YTmY*ԿU׿[ӕŨwԿ2׿ ^$2Ab=տ$: GSؿ;o Qտe eWٿ$F##\=׿Ajڿnp¿:;ٿȽRܿ+MAĿ9j@ۿQE}߿Ecƿ+[A߿Uvmv]Eʿ$5`Ugr,|$ao@Ͽn30TXߤC1 < }ҿ0ǥ+鿚{2׿k\'Zci8S%ؿ0/]nXҿ\mNٿ榤Ltҿ#ΛUJKٿgAKҿzS'Kd3$ٿwR"nҿyG*|¿jڿ3Fݒӿ (wÿj.ۿݚԿf1ſIq޿'qֿܔHǿKS9 ؿ8@¹>-ʿf'] ⿥ۿQ1οt?oJ-߿LѿZL鿸 ^:ys儾տF@^)w9i8SaTܿ?̀ȿ\m_ܿȿ#Λ pܿ訋=*ɿzS'AOruPݿhb4_~ɿyG*|¿aR:޿_(jʿ (wÿ_ĵw߿b1˿f1ſo%Tr IοܔHǿ_ p-@Ңп8@¹>-ʿ#gv6_xҿQ1οi9JտLѿg=rLgٿys儾տ'ZaxF߿ۿ`(Ý]L0D&TAП޿YTOV޿x[J<=[ӕX ߿qr}^$2Ɲy߿*&S3YV࿎K$F e4i>Rnp¿ay;Ѩ9z+MAĿ݅ḷ0Ccƿc"|r$4¿kv]Eʿ3GݨĿ"ao@Ͽ^o튛*ȿ0 < }ҿ>7JVE>ο{2׿b)V&6ҿŧ8Tm߿Q_䭼N!Hh4߿X׌ggNT֢'(2->b63@~hw0Ʒ3W4̈́Ph-_导.z(BΈ˰u>)xbZL+BfQjHrếmkO4(=jn9ր0翔iӃntwٿ τdЕӿE1Lٿ5i0ӿ'JPٿ n_RUh:<;ԿTrYڿu~5Կ6,ۿQJP]?ϾտA8<ܿZ9E:OV׿%t'߿25j͋ ^Fڿ7ēB⃝vݿIJ=>&Qb ῒ0$.lZw. H=P~x31Ѝ.:8͖`a^y":> ؿѻFտ`|CB_+0ؿ^ gտY${pؿugKտ-nU`ޅyZFؿ_`ֿ2v֌%13<ٿOޜfֿ|&6ۿi*׿l ډ_%jݿE+bڿ]fՃ?(xPIܿtKp+*^#= yjMJ@#KC DpQЕ,bi4_Q.bo Gih󇠼  V98O弁kۿ(- п,5ׁYۿKlB&п,6CܿKG"Qп"GgZ6@ܿǹ'_п:삼ݿYQ!ѿ%UW>߿%ei  ҿ 㲅 ῿ӿև@.GE⿞5Ғտ*̊ЄתiAؿ{鎼:F{TۿyNr^Ҽ2Ց&C'+sM .&uQhkB}п(M xؕE s޿[I_Ŀex3M޿zB~Ŀ=Lx}޿^DĿjN cy;-=߿Iſ\=-z(Ix>ްpſjM{!-i ƿg~4ٟ^pȿ^JE|rWl*xu5a˿xr 5翪οv]a ڿDFѿȰuFRDxVma,Gaտ +ZCˎ:<UٿiY30\h$X߿p7:Q߿ Ͱ/)ִ:d(ZʭB.簿yO:ڭ:-w`_"dx;^wnbS<fWJrIV=g1ARZ;ւᲿQ=@U^fxC9+VbAUzjYc5cˉzռyDVK apcm."G*1ļPԍHQfK+(_m8٭WF Pӏwſ:)ZT5]4+Iʿyx,|<%- t*ܷ2[d|f_`<ҪiA8^;c<@{T̬_%q&~k{<ϼ2Ցy"soG[&?mķ޿g 1jށ0?k3<߿zK㲿CE/}[?߿N:l ?vm0ge࿎䌻ӳ*H+?9ujD(æᴿs yv?P}⿘ǻ\? 9i俪,/ɂ?&+7d[BQ?ݽn[wl1: ?ᅴ4=0.ÿVntY?c`xI:Rǿ"2?(׼ ם|'Ϳ(3:-?-C ܿ\kJ%˿J#+I?.$4ܿMA˿;mx?Aվܿ(s ˿cJE@̿?O&fݿ,b̿ɡ/?1ݿU̿[/޲?ѰǷȁ߿MjغqοvG? &῞}lп.B"?ke #`4ҿM]V?HL}.a{hwԿȵ?onJܷۛ׿B?쿦QoۿS]n +%?p,,rOῥֶ ? ŕ-1忞tx?9@ڿt.w܁?@ڿi|%d?-P@+ۿ¿,O?Յ èۿig¿B+#?UkܿtT¿{oo?[qZ ޿WB_uÿ5UN?@ YDſr?9bǿ/$?81/KuYʿ;,F?QJ翳wdο!*_@?[cX [ҿP?b RֿOEU?0g8NۿP?mfɆֿwIIտ ;?EOD׿i Пiտ̽?P+W>׿wyտgR3?<ܺ:׿fjֿyfG?K~fؿPEv ֿa˚?h#aٿW ׿DqU?a,&ۿ ڿ=0eq5?G޿;ܿ?@F=-[࿾2u`?VoaYˈF⿏-v? +CB33?ٳ.bS?꿳qө?G- 7KuY2+?mfɆֿ#̴nѿl1ɫv?EOD׿LwW(ѿm?P+W>׿/Uѿ` ?<ܺ:׿ =pѿ bt|?K~fؿ 12ҿ^o?h#aٿcPK0L*ӿ{F{?a,&ۿwԿjN{?G޿XVֿp?@FB|OٿX ؼ+B?Voa㿾 Mqݿ8[? +*=4{h?ٳHt/h8pK}?G-Gla꿐4 ?J}Կ%iȿ/pU㿏@ʮ?BGqϿ=`Bs%ۿt^r]?(Ͽ3~Nۿ Ħ?r;IϿxXۿtϻ?V5Dпؠ+ܿnm5P?&N@>?j[UEä P+?N还y7;tg?_пT~׿dNup?пq׿VK?k:пWp'ؿ L=?@ѿp硖ؿ*\jd?l&%ѿbkZٿF?:ҿ0ڿ$c"?VĂeԿR?np¿ay;⿯9z?+MAĿޅḷ0?Ecƿc"fr$4?mv]Eʿ5Gݨ?$ao@Ͽ^o튛*?1 < }ҿ>7JVE>?{2׿d)V&6?i8SaTܿ ?̀?\m_ܿ~?#Λ pܿ٨=*?zS'EOruPݿYb4_~?zG*|¿aR:޿P(j? (wÿcĵw߿b1?f1ſo%Tr I?ܔHǿa g-@Ң?8@¹>-ʿ#gl6_x?Q1οm9J?Lѿ g=rLg?ys儾տ'ZaxF?ۿ`(Ý]?i8S%ؿ|0/]nX?\mNٿ榤Lt?#ΛUJKٿgAK?zS'Pd3$ٿwR"n?yG*|¿jڿ-Fݒ? (wÿo.ۿݚ?f1ſNq޿|'q?ܔHǿKK9 ?8@¹>-ʿj'] ⿜?Q1οt?o@-?Lѿ`L鿲 ^:?ys儾տM@<y[?ۿP>^)w|9?L0D&ilftԿC1xf?YTtY*ԿP?[ӕŨwԿ2?^$2Ab=տ: GS?Co Qտ_ eW?$F,#\=׿;j?np¿C;ٿȽR?+MAĿ9j@ۿIE}?Bcƿ+[A߿Pv?jv]Eʿ*5`Ogr,|? ao@Ͽv30MXߤC?. < }ҿ:ǥ+鿒?~{2׿ k\'Zc?ç8amϿ̡w?L!Hh4Ͽhr[?eNTܢ'(п?43@~hпYѭk?ķ3W4̈́пg oiN?.z(Bѿ?u>)xiZL+Bfӿڕ?rếukOտSt?=jn9ր0׿x{4?n-=߿I?OMS)Ix>̰p?͂|LST!-i ?`9mU4ٟ⿫^p?R7XtWl*xu5a?g[7翏?@ Ƃ'_ڿD6?.>osbDxVmO,Ga?!6;of$<U? k_h$X?3P3߿ei  ?IA8< ῴ?!_:N ؿѻF?G2i=&pd+0ؿ^ g?-wQppؿtgK?_ 7~p~ZFؿ_`?V~c!q+13<ٿIޜf?B6s r-6ۿi*?Isf%jݿ>+b?aA˒uك?(pPI?*AxKp+*Y#=?U6K{RJ@#EC ?ۯgБ1bi4?ʰ(&Q.bo ?,7   Q98? >|<"tӿ8tw?(x}?hag{<ӿ ?/@~<5Ғտ?.GE?У\j)*<ܪiAؿτ?gK̃׿AIKP2n?>ܺ:׿.`(0?M~fؿLk o㇞?h#aٿM.#4?b,&ۿ$WQ檆?G޿Ƞ܊km?@FwkQAC?Voa*o|ҧ4J? +翡#dv0D?ٳ쿳{?<ſ)?H-񿀬ewʿ찖P?mfɆֿCl?1[#?GOD׿2L~ ?&żD?P+W>׿IKP2?n?>ܺ:׿`?(0?M~fؿLk ?p㇞?h#aٿ#.?$4?b,&ۿWQ?檆?G޿܊?km?@Fwk?QAC?Voa㿶*o|?ҧ4J? +|#dv?0D?ٳ쿆{?=zJ?',?)ϿxºǾ?Z?s;IϿu?_?V5DпX5{?r?&-ʿдoK16?Q1οSYS";?LѿR=:p N=?ts儾տ.yyJuZG?ۿe(ſ9?i8S<|? Pxî?\m(?)g[?#Λy .?- j:?zS'pGl?Q?xG*|¿e?/ &d? (wÿjO?C?f1ſmڰ?vߚ ?ؔHǿ;u[c??4@¹>-ʿ8д?oK16?Q1οxSYS?$;?Lѿ=:p?N=?us儾տ.yyJ?wZG?ۿe(?9?L0D&Յ!0?Z?YTXcO?1Ll?[ӕ^O?K?^$2Y.? w?Ŋ?Fӿ?$F-Nqǯ?$?np¿ ?ްl?+MAĿB%!??Ccƿ7K ?`O?kv]Eʿ}̗?ݩ?"ao@Ͽ`XF?\Q{?0 < }ҿ=mW?%3c?{2׿\?֑?+s<;kȿot?Ȅ4YOtTI?Z/|tv1~<@ ҿ=Ti?i< C]eտZ?{yn08?;h~@Xÿi?귃<?UPƿ j?w.[<Kcnʿ2?20˃<]NW4?5E#?A<>@X?i?+<>UP? j?Wfh<ƥKcn?2o?G[&?mķ?Y 1?jށ0?l3o?>͒Gd9ujD?æ?YtreP}?ǻ?>g 9i??ASœi&+7?d?etC˝mݽ?f[wl1?p?4=0.?7^sc`xI?-R?_]9$x(׼ ?ǝ|'?$:~:@?g.w?݁?@?i|?&d?.P@+? ?-O?Յ è?ig?B+#?Uk?xtT?|oo?[qZ ?IB_u?6UN?@ Y?D?r??9b?0$?81?KuY?<,F?QJ?wd?"*_@?[cX? [?P?b?R?OEU?2g8?N?Q?-C ?UkJ%?J#+I?.$4?MA?;mx?Aվ?!s ?cJE@̿?O&f?%b?ɡ/?1?N?^/޲?ѰǷȁ?Mjغq?zG? &?}l?3B"?ke ?#`4?R]V?HL}.?\{hw?ȵ?on?Eܷۛ?B??Qo?V]n +%?p,?)rO?ֶ ? ?-1?tx?:@?m.w?BWy<@?i|?d<.P@+??1]J<Յ è?ig?ó5V<Uk?~tT?e_f<[qZ ?OB_u?@r><@ Y?D?<3Ԋ<?9b?x<81?$KuY?K\1<QJ?wd?4N=6<[cX? [?<b?R?neؑ<0g8?N?DZ8k'<J}?i?2pU?@ʮ?mfɆ? ̴n?t1ɫv?GOD?LwW(?m?P+W>?/U?h ?>ܺ:?=p?bt|?M~f? 12?go?h#a?_PK0L*?F{?b,&?w?oN{?G?TV?v?@F?>|O?_ ؼ+B?Voa? Mq?8[? +?*?E4{h?ٳ?Dt/h?=pK}?H-?Bla?4 ?mfɆ?wII? ;?GOD?g Пi?,̽?P+W>?wy?xR3?>ܺ:?fj?fG?M~f?PEv ?a˚?h#a?W ?NqU?b,&? ?H0eq5?G?;??@F?=-[?2u`?Voa?WˈF?-v? +?CB?E3?ٳ?+bS??qө?H-? 7?XuY2+?J}?i?'AS><W ?7pQ?4rc<ۡ[?Ugj?%2<@3?a ?Z]<Ul),?Y`?+)ޙ<b!??N><?l<=?hy<O/?Kf ?(5J<r߅?X٬?@Q^ P<V ;?IN??X. <J%?j2?ΔZ<w+D}?PUŜ?wm<?a?>pU?Õ}<!x?5t?k?)J?"?N??6q?z/?`?q?aj(|z?AC&e?!6G\D?hǢm?AS7?0ma??G?&HjC?)R? 4?+??|#?uN?m @?QNE?}1vD?ij?!e:?`H`?n!f?jP/T?Yu 6 ?^|?a1a?nB? ?S-?CGq?Уr?-돣?)?GP?U$k5?s;I?6#?!k?V5D?,?Je?&?N@>?j[U?Eä ?]+?N?y7;?tg?!x? 5t?Pǣ<)J?"?uН<3q?/?q<q?jj(|z?K <6G\D?qǢm?ö ˟<-ma??9ZF<&HjC?.R?u1 !<+??;4<uN?m @?4?d<z1vD?ij?%ө<]H`?ɜn!f?nɆj<Wu 6 ?^|?v0qy<nB? ?Vs.<˧8?Nm? ̡w?T!Hh?4?hr[?mNT?Ӣ'(??<3@?~h?Yѭk?ͷ3W?4̈́?n oiN?.z?(B??u>)x?\ZL+Bf?ە?r?gkO?St?=jn9?ր0?|{4?n-?f'] ??Q1?t?o?I-?L?ZL? ^:?vs儾?F@^)w?9?i8S?aT??̀?\m?_??#Λ? p?樋=*?zS'?BOruP?fb4_~?xG*|?aR:?](j? (w?`ĵw?b1?f1?o%T?r I?ؔH?` ?o-@Ң?4@¹>-?#g?u6_x?Q1?k9?J?L?g=?rLg?us儾?'Z?axF??`(?Ý]?L0D&?UAП??YT?OV?r[J<=?[ӕ?X ?kr}?^$2?ǝy?*&??S3YV?K?$F? e4?c>R?np?ay;?ʨ9z?+MA?݅l?̣0?Dc?c"?wr$4?lv]E?3G?ݨ?#ao@?^o튛? *?0 < }?>7?JVE>?{2?b)V?&6?ǧ8?Tm?8D<P!Hh?4?;PO"t<iNT?֢'(? ǟ<83@?~h?Ȣ9-<ȷ3W?4̈́?B#bG<.z?(B?)<u>)x?bZL+Bf?b <r?mkO?VJ<=jn9?ր0?8LO*<n<s?;^?"<s ??;?1<XCJ?H?B t<N?>o?G[&mķ?a 1?lށ0k3?wy?lR3=ܺ:?fj?~fGL~f?PEv ?a˚h#a?W ?GqUa,&? ?@0eq5¿G?;?ÿ@F?=-[?2u`ƿVoa?XˈF?-vɿ +?CB?73οٳ?,bS??qөҿH-? 7?NuY2+׿mfɆ?"̴n?o1ɫvͿGOD?LwW(?mͿP+W>?/U?c Ϳ>ܺ:?=p?bt|οM~f? 12?boϿh#a?bPK0L*?}F{пb,&?w?lN{ҿG?WV?sӿ@F?A|O?\ ؼ+BֿVoa? Mq?8[ٿ +?*?A4{h޿ٳ?Gt/h?;pK}H-?Fla?4 J}?i?0pU?@ʮBGq?<`Bs%?{^r](?2~N? Ħr;I?xX?tϻV5D?ؠ+?um5P&?N@>̿j[U?Eä ?U+ѿN?y7;?tgտ_?T~?hNup˿?q?VK˿k:?Wp'?L=˿@?o硖?/\jd̿l&%?akZ?FͿ:?0?)c"οVĂe?;f?\пMng?Ā?Poҿ '1?M?Zt̺Կƭ? ?L9e׿|l5?*ӆ?>Su *RܿqS#?Ս8?Lo28?GkD?-U_vCGq?Уr?)돣Կ)?GP?U$k5Կs;I?6#?!kԿV5D?,?JeԿ&Rnp?ay;?9z+MA?ޅl?̣0Ec?c"?mr$4¿mv]E?4G?ݨĿ$ao@?^o튛?*ȿ1 < }?>7?JVE>ο{2?c)V?&6ҿi8S?aT? ?̀ȿ\m?_?ȿ#Λ? p?ݨ=*ɿzS'?COruP?]b4_~ɿxG*|?aR:?T(jʿ (w?aĵw?b1˿f1?o%T?r IοٔH?` ?j-@Ңп5@¹>-?#g?p6_xҿQ1?l9?JտL?g=?rLgٿus儾?'Z?axF߿?`(?Ý]i8S?%?~0/]nXҿ\m?N?榤Ltҿ#Λ?UJK?gAKҿzS'?Od3$?wR"nҿxG*|?j?/Fݒӿ (w?n.?ݚԿf1?Mq?~'qֿؔH?K?M9 ؿ4@¹>-?i'] ?ۿQ1?t?o?B-߿L?^L? ^:us儾?J@^)w?~9L0D&?glft?E1xf׿YT?rY*?R׿[ӕ?Ũw?2׿^$2?Ab=? : GSؿ?Ao Q?a eWٿ$F?*#\=?=jڿnp?A;?ȽRܿ+MA?9j@?LE}߿Ac?+[A?Rviv]E?)5`?Rgr,|ao@?t30?PXߤC. < }?8ǥ+?~{2? k?\'Zcç8?Ym? ̡wۿL!Hh?4?hr[ۿeNT?آ'(?ۿ43@?~h?Yѭkܿķ3W?4̈́?k oiNݿ.z?(B?޿u>)x?eZL+Bf?ەr?pkO?St=jn9?ր0?z{4noG[&mķ?^ 1mށ0k3?4IKP2?nֿ=ܺ:? `?(0ֿL~f?Lk ?p㇞׿h#a?=.?$4ؿa,&?WQ?檆ۿG?܊?kmݿ@F?wk?QACVoa?ޣ*o|?ҧ4J +?#dv?0Dٳ?{??%IKP2nֿ<ܺ:?`(0ֿK~f?Lk p㇞׿h#a?-.$4ؿa,&?WQ檆ۿG?܊kmݿ@F?wkQACVoa?ƣ*o|ӧ4J +?#dv1Dٳ?{?<ſ)G-?Vewʿ찖PJ}?iȿ2pU㿒@ʮCGq?]=zJ? ',ڿ)?ºǾ?Zۿs;I??_ۿV5D?X5{?rۿ&-?tд?oK16Q1?SYS?#;L?,=:p? N=vs儾?.yyJ?vZG?e(?9i8S?]| Pxî޿\m?3()g[޿#Λ? .- j:߿zS'?GlQ߿yG*|?e/ &d (w?OCf1?mڰvߚ ڔH?Qu[c6@¹>-?PдoK16Q1?SYS$;L?=:pN=vs儾?.yyJwZG?e(ſ9L0D&?ۅ!0ĿZݿYT?XcOĿ0Llݿ[ӕ?^OĿK޿^$2?`.Ŀ w޿?ŊſEӿ߿$F?-Nqǯƿ$np? ȿްl+MA?J%!˿Cc?7K ο`Okv]E?}̗ѿݩ"ao@?gXFԿ\Q{0 < }?EmWٿ%3c{2?f߿֑ŧ8?OmϿ ̡wۿN!Hh?4Ͽhr[ۿgNT?Ӣ'(пۿ63@?~hпYѭkܿƷ3W?4̈́пm oiNݿ.z?(Bѿ޿u>)x?\ZL+Bfӿەr?gkOտSt=jn9?ր0׿{{4no¿jmķ?a 1¿- 9k30g8?NmfɆ?̴nѿu1ɫvͿEOD?LwW(ѿmͿP+W>?/Uѿi Ϳ<ܺ:?=pѿbt|οK~f?12ҿhoϿh#a?^PK0L*ӿF{пa,&?wԿoN{ҿG?SVֿvӿ@F?<|Oٿ_ ؼ+BֿVoa? Mqݿ8[ٿ +?*F4{h޿ٳ?Ct/h>pK}G-?Ala꿘4 mfɆ?wIIտ ;FOD?f Пiտ2̽P+W>?wyտ~R3=ܺ:?fjֿfGL~f?PEv ֿa˚h#a?W ׿QqUa,&? ڿK0eq5¿G?;ܿÿ@F?=-[2u`ƿVoa?WˈF⿡-vɿ +?CBI3οٳ?*bS?qөҿH-? 7[uY2+׿J}?iؿyyVW ?7pQؿG򣅁ۡ[?Ugjٿ̉3ͬ@3?a ٿ~-sARUl),?Y`ڿAn5,<b!?ۿLJjׯ?l<=޿65UO/?Kf |x}B r߅?X٬⿷9mSshV ;?IN x<J%?j2XpU)*ƼBGq?Уrӿ-돣Կ(?GPӿU$k5Կr;I?6#ӿ!kԿV5D?,ԿJeԿ&N@>̿j[U?Dä c+ѿN?y7;Ƞtgտ!x? 5tݿ1H)J?"ݿCҌ2q?/ݿصA;>q?jj(|z޿F&D6G\D?qǢm߿$1L0 ,ma?QȨ&HjC?.Rx ݌+?yuN?m @˲%y1vD?ij&ٻ\H`?ɜn!fB#~Vu 6 ?^|`rļnB? >ɼL0D&?blftԿH1xf׿YT?mY*ԿU׿[ӕ?ŨwԿ2׿^$2?Ab=տ$: GSؿ?;o Qտe eWٿ$F?##\=׿Ajڿnp?:;ٿȽRܿ+MA?9j@ۿQE}߿Bc?+[A߿Uvjv]E?$5`Ugr,| ao@?n30TXߤC. < }?0ǥ+鿚~{2?k\'Zci8S?%ؿ0/]nXҿ\m?Nٿ榤Ltҿ#Λ?UJKٿgAKҿzS'?Kd3$ٿwR"nҿwG*|?jڿ3Fݒӿ (w?j.ۿݚԿf1?Iq޿'qֿהH?KS9 ؿ3@¹>-?f'] ⿥ۿQ1?t?oJ-߿L?ZL鿸 ^:ts儾?F@^)w9i8S?aTܿ?̀ȿ\m?_ܿȿ#Λ? pܿ騋=*ɿzS'?AOruPݿib4_~ɿwG*|?aR:޿`(jʿ (w?_ĵw߿b1˿f1?o%Tr IοהH?_ q-@Ңп3@¹>-?#gx6_xҿQ1?i9JտL?g=rLgٿts儾?'ZaxF߿?`(Ý]L0D&?TAП޿YT?OV޿y[J<=[ӕ?X ߿rr}^$2?Ɲy߿*&?S3YV࿐K$F? e4k>Rnp?ay;Ө9z+MA?݅ḷ0Bc?c"}r$4¿jv]E?3GݨĿ ao@?^o튛*ȿ. < }?>7JVE>ο~{2?b)V&6ҿƧ8?Tm߿O!Hh?4߿N迯hNT?֢'(࿏K 73@?~he놁2TǷ3W?4̈́ Xvְ.z?(Bp|u>)x?bZL+Bf㿟uNr?mkO_14=jn9?ր0翶طnoG[&?mķ?f 1iށ0?k3?wyտcR3?=ܺ:?fjֿufG?L~f?PEv ֿa˚?h#a?W ׿BqU?a,&? ڿ;0eq5?G?;ܿ?@F?=-[࿻2u`?Voa?YˈF⿋-v? +?CB.3?ٳ?-bS?꿰qө?H-? 7GuY2+?mfɆ?$̴nѿk1ɫv?EOD?LwW(ѿm?P+W>?/Uѿ_ ?<ܺ:? =pѿ bt|?K~f? 12ҿ]o?h#a?dPK0L*ӿ{F{?a,&?wԿjN{?G?YVֿp?@F?C|OٿX ؼ+B?Voa? Mqݿ8[? +?*<4{h?ٳ?Ht/h8pK}?F-?Gla꿐4 ?J}?&iȿ/pU㿏@ʮ?BGq?=`Bs%ۿq^r]?(?3~Nۿ Ħ?r;I?xXۿtϻ?V5D?٠+ܿkm5P?&N@>?j[U?Fä N+?N?y7;tg?_?T~׿bNup??q׿VK?k:?Wp'ؿ L=?@?p硖ؿ(\jd?l&%?bkZٿF?:?0ڿ"c"?WĂe?R?np?ay;⿭9z?+MA?ޅḷ0?Cc?c"er$4?kv]E?5Gݨ?"ao@?^o튛*?0 < }?>7JVE>?{2?d)V&6?i8S?aTܿ?̀?\m?_ܿ}?#Λ? pܿب=*?zS'?EOruPݿXb4_~?zG*|?aR:޿O(j? (w?cĵw߿b1?f1?o%Tr I?ܔH?a g-@Ң?8@¹>-?#gl6_x?Q1?m9J?L? g=rLg?ys儾?'ZaxF??`(Ý]?i8S?%ؿ|0/]nX?\m?Nٿ榤Lt?#Λ?UJKٿgAK?zS'?Pd3$ٿwR"n?yG*|?jڿ-Fݒ? (w?o.ۿݚ?f1?Nq޿|'q?ܔH?KK9 ?8@¹>-?j'] ⿜?Q1?t?o@-?L?`L鿲 ^:?ys儾?M@<y[??P>^)w|9?L0D&?ilftԿB1xf?YT?tY*ԿO?[ӕ?ŨwԿ2?^$2?Ab=տ: GS??Co Qտ^ eW?$F?,#\=׿:j?np?C;ٿȽR?+MA?9j@ۿHE}?Cc?+[A߿Pv?kv]E?*5`Ogr,|?"ao@?v30MXߤC?0 < }?:ǥ+鿑?{2? k\'Zc?ȧ8?amϿ̡w?Q!Hh?4Ͽhr[?jNT?ܢ'(п?93@?~hпYѭk?ʷ3W?4̈́пh oiN?.z?(Bѿ?u>)x?iZL+Bfӿڕ?r?ukOտSt?=jn9?ր0׿y{4?n?AIKP2n?>ܺ:?.`(0?M~f?Lk o㇞?h#a?M.#4?b,&?$WQ檆?G?Ƞ܊km?@F?wkQAC?Voa?*o|ҧ4J? +?#dv0D?ٳ?{?<ſ)?H-?ewʿ찖P?mfɆ?Cl?1[#?GOD?2L~ ?&żD?P+W>?IKP2?n?>ܺ:?`?(0?M~f?Lk ?p㇞?h#a?#.?$4?b,&?WQ?檆?G?܊?km?@F?wk?QAC?Voa?*o|?ҧ4J? +?|#dv?0D?ٳ?{?=zJ? ',?)?xºǾ?Z?s;I?u?_?V5D?X5{?r?&-?дoK16?Q1?SYS";?L?O=:p N=?us儾?.yyJuZG??e(ſ9?i8S?<|? Pxî?\m?(?)g[?#Λ?y .?- j:?zS'?pGl?Q?xG*|?e?/ &d? (w?jO?C?f1?mڰ?vߚ ?ؔH?;u[c??4@¹>-?8д?oK16?Q1?xSYS?$;?L?=:p?N=?us儾?.yyJ?wZG??e(?9?L0D&?Յ!0?Z?YT?XcO?1Ll?[ӕ?^O?K?!^$2?Y.? w??Ŋ?Fӿ?$F?-Nqǯ?$?np? ?ްl?+MA?B%!??Fc?7K ?`O?nv]E?}̗?ݩ?%ao@?`XF?\Q{?2 < }?=mW?%3c?{2?\?֑?ԛ`                  !!" ! # #$!$%"%&# $! %"!'#'($()%)*&*+'#($#)%$*&%,',-(-.)./*/0+01,'-('.)(/*)0+*2323432"535646753643"&858969:7:;85"965:76&+<8<=9=>:>?;?@<8&=98>:9?;:+1A<AB=BC>CD?DE@EFA<+B=<C>=D?>E@?2G24HGHIHG247JHJKIKLJH4KIH7;MJMNKNOLOPMJ7NKJOLK;@QMQRNRSOSTPTUQM;RNMSONTPO@FVQVWRWXSXYTYZUZ[VQ@WRQXSRYTSZUTG\GI]\]^]\GIL_]_`^`a_]I`^]LPb_bc`cdadeb_Lc`_da`PUfbfgcghdhieijfbPgcbhdciedU[kfklglmhmninojopkfUlgfmhgnihoji\\^qqq\^arqrssrq^sqaetrtusuvv trausrvsejwtwxuxyvyz zwtexutyvuz vjp{w{|x|}y}~z~{wj|xw}yx~zyz,-,.-/.0/10,-./0A1BACBDCEDFEABCDEVFWVXWYXZY[ZVWXYZk[lkmlnmonpoklmno{p|{}|~}~{|}~                  ! " #"! !"$%$"&%#"$"#%'('$)(%*)&$'$%(%&)+,+'-,(.-)/.*'+'(,()-)*.0 10+21,32-43.54/+0+,1,-2-.3./46!7#!876!679&#:97;:8#7978:<*&=<9>=:?>;&9<9:=:;>@/*A@<BA=CB>DC?*<@<=A=>B>?CE5/FE@GFAHGBIHCJID/@E@AFABGBCHCDI6K86K6KL;8MLKM8KLKMN?;ONLPOMP;LNLMOMPQD?RQNSROTSPT?NQNOROPSPTUJDVUQWVRXWSYXTYDQUQRVRSWSTXTY[\Z]^[^_\\[^`a]ab^bc_^]a_^bde`efafgbghca`ebafcbgijdjkeklflmgmnhedjfekgflhgmijklmnjikjlkmlnm\oZ_p\pqoo\pcr_rspstqp_rqpshucuvrvwswxtrcusrvtswnyhyzuz{v{|w|}xuhyvuzwv{xw|nyz {  |  }ynzy{z|{ }| o~Zqo~~otqqxtt}xx } }~Z~~ 0011223344501234Z5EEFFGGHHIIJEFGHI[Z][[`]]d``iddJUUVVWWXXYYiUVWXiY`p#                   #$$#$%%$%&&%&''&'(('())())#0$1#10#$1%2$21$%2&3%32%&3'4&43&'4(5'54'(5)6(65()6)6)$###%$$$&%%%'&&&(''')((())) =J >K= KJ=  >K ?L> LK>  ?L @M? ML?  @M AN@ NM@  ANBOAONABOCPBPOBCPCPCJWKXJXWJKXLYKYXKLYMZLZYLMZN[M[ZMN[O\N\[NO\P]O]\OP]P]P#Wd$XeW$edW$$Xe%YfX%feX%%Yf&ZgY&gfY&&Zg'[hZ'hgZ''[h(\i[(ih[((\i)]j\)ji\))]j]j]0dq1erd1rqd11er2fse2sre22fs3gtf3tsf33gt4hug4utg44hu5ivh5vuh55iv6jwi6wvi66jwjwjK J  J JL K  K KM L  L LN M  M MON N NPOOOPPPX$W$W$#WY%X%X%$XZ&Y&Y&%Y['Z'Z'&Z\([([('[])\)\)(\]])]e$1d1$#d1#0df%2e2%$e2$1eg&3f3&%f3%2fh'4g4'&g4&3gi(5h5('h5'4hj)6i6)(i6(5ij)j)6j=~>~>~>>????@@@@AAAABBBBCCCCJKKKKLLLLMMMMNNNNOOOOPPPPWXXXXYYYYZZZZ[[[[\\\\]]]]deeeeffffgggghhhhiiiijjjjqrrrrssssttttuuuuvvvvwwww>KK>=K=J?LL?>L>K@MM@?M?LANNA@N@MBOOBAOANCPPCBPBOCCPKXXKJXJWLYYLKYKXMZZMLZLYN[[NM[MZO\\ON\N[P]]PO]O\PP]XeeXWeWdYffYXfXeZggZYgYf[hh[ZhZg\ii\[i[h]jj]\j\i]]jerredrdqfssfesergttgftfshuuhgugtivvihvhujwwjiwivjjw~         ~~   '(('())()**)*++*+,,+,--,--455456656776788789989::9::'4A(5B4(BA4((5B)6C5)CB5))6C*7D6*DC6**7D+8E7+ED7++8E,9F8,FE8,,9F-:G9-GF9--:G:G:5(4(4('46)5)5)(57*6*6*)68+7+7+*79,8,8,+8:-9-9-,9::-:0N1O0ON01O2P1PO12P3Q2QP23Q4R3RQ34R5S4SR45S6T5TS56T6T64N[5O\N5\[N55O\6P]O6]\O66P]7Q^P7^]P77Q^8R_Q8_^Q88R_9S`R9`_R99S`:TaS:a`S::TaTaTA[hB\i[Bih[BB\iC]j\Cji\CC]jD^k]Dkj]DD^kE_l^Elk^EE_lF`m_Fml_FF`mGan`Gnm`GGananaO5N5N54NP6O6O65OQ7P7P76PR8Q8Q87QS9R9R98RT:S:S:9STT:T\5B[B54[B4A[]6C\C65\C5B\^7D]D76]D6C]_8E^E87^E7D^`9F_F98_F8E_a:G`G:9`G9F`a:a:Ga0qu1rvq1vuq11rv2swr2wvr22sw3txs3xws33tx4uyt4yxt44uy5vzu5zyu55vz6w{v6{zv66w{w{wNuOvuOuOOvPwvPvPPwQxwQwQQxRyxRxRRySzySySSzT{zTzTT{{{[\\\\]]]]^^^^____````aaaahiiiijjjjkkkkllllmmmmnnnnv1OuO10uO0Nuw2PvP21vP1Ovx3QwQ32wQ2Pwy4RxR43xR3Qxz5SyS54yS4Ry{6TzT65zT5Sz{6{6T{O\\ON\N[P]]PO]O\Q^^QP^P]R__RQ_Q^S``SR`R_TaaTSaS`TTa\ii\[i[h]jj]\j\i^kk^]k]j_ll_^l^k`mm`_m_lanna`n`maanqrrrrssssttttuuuuvvvvwwwwuvvvvwwwwxxxxyyyyzzzz{{{{rvvrqvquswwsrwrvtxxtsxswuyyutytxvzzvuzuyw{{wv{vzww{vvuuwwvvxxwwyyxxzzyy{{zz{{                         !! !""!"##"#$$#$   $+,,+, --, -!. .- !."/!/.!"/#0"0/"#0$1#10#$1  $ 1$          !   "!!!#"""$### $$$'8(9'98'(9):(:9():*;);:)*;+<*<;*+<,=+=<+,=->,>=,-> - >-'AE(BFA(FEA((BF)CGB)GFB))CG*DHC*HGC**DH+EID+IHD++EI,FJE,JIE,,FJ-GKF-KJF--GK G KG8ER9FSE9SRE99FS:GTF:TSF::GT;HUG;UTG;;HU<IVH<VUH<<IV=JWI=WVI==JW>KXJ>XWJ>>KX  K XK F(9E9('E9'8EG):F:)(F:(9FH*;G;*)G;):GI+<H<+*H<*;HJ,=I=,+I=+<IK->J>-,J>,=J  K -K ->KAh_Bi`hB`_hBBi`CjaiCa`iCCjaDkbjDbajDDkbElckEcbkEElcFmdlFdclFFmdGnemGedmGGnenenE_lF`m_Fml_FF`mGan`Gnm`GGanHboaHonaHHboIcpbIpobIIcpJdqcJqpcJJdqKerdKrqdKKer e re RlySmzlSzylSSmzTn{mT{zmTTn{Uo|nU|{nUUo|Vp}oV}|oVVp}Wq~pW~}pWWq~XrqX~qXXrrr`BF_FBA_FAE_aCG`GCB`GBF`bDHaHDCaHCGacEIbIEDbIDHbdFJcJFEcJEIceGKdKGFdKFJd e Ge GKemFSlSFElSERlnGTmTGFmTFSmoHUnUHGnUGTnpIVoVIHoVHUoqJWpWJIpWIVprKXqXKJqXJWq r KrKXrhiiiijjjjkkkkllllmmmmnnnn_````aaaabbbbccccddddeeeelmmmmnnnnooooppppqqqqrrrryzzzz{{{{||||}}}}~~~~i``ih`h_jaajiai`kbbkjbjalcclkckbmddmldlcneenmemdnne`mm`_m_lanna`n`mboobaoancppcbpbodqqdcqcperredrdqeermzzmlzlyn{{nm{mzo||on|n{p}}po}o|q~~qp~p}rrqq~rr+,++,-,,-.--./../0//01001 11                                        "##"#$$#$%%$%&&%&''&'(('(("/#0"0/"#0$1#10#$1%2$21$%2&3%32%&3'4&43&'4(5'54'(5(5(/<0=/=</0=1>0>=01>2?1?>12?3@2@?23@4A3A@34A5B4BA45B 5 B5                    #"""$###%$$$&%%%'&&&('''(((0///100021113222433354445558I9J8JI89J:K9KJ9:K;L:LK:;L<M;ML;<M=N<NM<=N>O=ON=>O !>!O>8RV9SWR9WVR99SW:TXS:XWS::TX;UYT;YXT;;UY<VZU<ZYU<<VZ=W[V=[ZV==W[>X\W>\[W>>X\ "X "\X IVcJWdVJdcVJJWdKXeWKedWKKXeLYfXLfeXLLYfMZgYMgfYMMZgN[hZNhgZNN[hO\i[Oih[OO\i!"#\!#i\!W9JVJ98VJ8IVX:KWK:9WK9JWY;LXL;:XL:KXZ<MYM<;YM;LY[=NZN=<ZN<MZ\>O[O>=[O=N[" !\! >\!>O\RypSzqySqpySSzqT{rzTrqzTT{rU|s{Usr{UU|sV}t|Vts|VV}tW~u}Wut}WW~uXv~Xvu~XXv$$vVp}Wq~pW~}pWWq~XrqX~qXXrYsrYrYYsZtsZsZZt[ut[t[[u\vu\u\\v"$%v"%v"c}d~}d}dd~e~e~eeffffgggghhhhiiii#%&#&#qSWpWSRpWRVprTXqXTSqXSWqsUYrYUTrYTXrtVZsZVUsZUYsuW[t[WVt[VZtvX\u\XWu\W[u$"v"Xv"X\v~Wd}dWV}dVc}Xe~eXW~eWd~YffYXfXeZggZYgYf[hh[ZhZg\ii\[i[h%"##"\#\iyzzzz{{{{||||}}}}~~~~''pqqqqrrrrssssttttuuuuvvvv$'($($}~~~~%()%)%&)*&*&zqqzyqyp{rr{zrzq|ss|{s{r}tt}|t|s~uu~}u}tvv~v~u'$$$vq~~qp~p}rrqq~ssrrttssuuttvvuu($%%$v%v~~}}~~)%&&%&++'+,','(,-(-()-.).)*./*/*+''','(('(-())().)**)*< = <  <= >= =>?>>?@??@A@@ABAAB 0B0B       +01+1+&''&'(('())()**)*++*+,,+,,12,2,,&3'4&43&'4(5'54'(5)6(65()6*7)76)*7+8*87*+8,9+98+,9-23,-39,-3@4A3A@34A5B4BA45B6C5CB56C7D6DC67D8E7ED78E9F8FE89F.349.4F9.@MAN@NM@ANBOAONABOCPBPOBCPDQCQPCDQERDRQDERFSESREFS/45F/5SF/       0+++1+,,+,'&&&(''')(((*)))+***,+++2,-,-,,-,4333544465557666877798883-.9.-9.9A@@@BAAACBBBDCCCEDDDFEEE4./F/.F/FIZJ[I[ZIJ[K\J\[JK\L]K]\KL]M^L^]LM^N_M_^MN_O`N`_NO`!6O6`OIcgJdhcJhgcJJdhKeidKihdKKeiLfjeLjieLLfjMgkfMkjfMMgkNhlgNlkgNNhlOimhOmlhOOim!#7i!7mi!Zgt[hug[utg[[hu\ivh\vuh\\iv]jwi]wvi]]jw^kxj^xwj^^kx_lyk_yxk__ly`mzl`zyl``mz678m68zm6hJ[g[JIg[IZgiK\h\KJh\J[hjL]i]LKi]K\ikM^j^MLj^L]jlN_k_NMk_M^kmO`l`ONl`N_l7!6m6!Om6O`mcddddeeeeffffgggghhhhiiii#&9#9#ghhhhiiiijjjjkkkkllllmmmm79:7:7tuuuuvvvvwwwwxxxxyyyyzzzz8:;8;8dhhdchcgeiiedidhfjjfejeigkkgfkfjhllhglgkimmihmhl9#77#i7imhuuhgugtivvihvhujwwjiwivkxxkjxjwlyylkykxmzzmlzly:7887m8mz&*<&<&9<=9=9:=>:>:;>?;?;<&99&9=9::9:>:;;:;*/@*@*<@A<A<=AB=B=   >BC>C >  ?CD ?D ?@*<<*<A<==<=B=>>=> C>? ?> ? MNMMNONNOP O OP Q!P! PQ!R"Q"!QR"S#R#"RS#/5ES/E#S/*++*+,,+, --, -!. .- !."/!/.!"/#0"0/"#0@EF#@F0#@*7+8*87*+8,9+98+,9-:,:9,-:.;-;:-.;/<.<;./<0=/=</0=AFG0AG=0A7D8E7ED78E9F8FE89F:G9GF9:G;H:HG:;H<I;IH;<I=J<JI<=JBGH=BHJ=BDQERDRQDERFSESREFSGTFTSFGTHUGUTGHUIVHVUHIV JWI WVI  JWCHIJCIWJCQ^R_Q_^QR_S`R`_RS`TaSa`STaUbTbaTUbVcUcbUVcWdVdcVWdDIJWDJdWD !   "!!!#"""E/@#@/#@#+***,+++-,,,.---/...0///F@A0A@0A087779888:999;:::<;;;=<<<GAB=BA=B=EDDDFEEEGFFFHGGGIHHHJ I I IHBCJCBJC JRQQQSRRRTSSSUTTTVUUUW V VVICDWDC WD WZ[ZZ[\[[\]\\]^]]^_^^_`__`6``Ztk[ult[lkt[[ul\vmu\mlu\\vm]wnv]nmv]]wn^xow^onw^^xo_ypx_pox__yp`zqy`qpy``zq68Kz6Kqz6klkklmllmnmmnonnopoopqppqKqql[k[ZkZkm\l\[l[ln]m]\m\mo^n^]n]np_o_^o^oq`p`_p_pK6q6`q`qtxuyuyxuuyvzvzyvvzw{w{zww{x|x|{xx|y}y}|yy}z~z~}zz~8;L8L~8kxlyxlxllymzymymmzn{znznn{o|{o{oo|p}|p|pp}q~}q}qq~KLM~KM~K                  Myulxlutxltkxzvmymvuymuly{wnznwvznvmz|xo{oxw{own{}yp|pyx|pxo|~zq}qzy}qyp}L8K~K8z~Kzq~llkkmmllnnmmoonnppooqqppMKKqq;?N;N;xyyyyzzzz{{{{||||}}}}~~~~LNOLOLMOPMPM = > >=  > ? ?>  ? @ @?  @ A A@  ABBABCCBCPCyyyxzzzy{{{z|||{}}}|~~~}N;LL;L~yyxxzzyy{{zz||{{}}||~~}}OLMML~M~                 PMM?DQ?Q?NQRNRNORSOSOPSTPTP=~>>~>>????@@@@AAAABBBBCCCCTQ?NN?NRNOONOSOPPOP>>>=???>@@@?AAA@BBBACCCBTPPC^_^^_`__`a``abaabcbbcdccdDJUdDUdDQUVQVQ                   RVWRW R                  SWX SX S!""!"##"#$$#$%%$%&&%&''&'TXYTY'T~!"!!"#""#$##$%$$%&%%&'&&'Y''UDQQDQVQRRQR                 WRS SR S XSTTST"!!~!#"""$###%$$$&%%%'&&&YT'T''.H;/I<;/I;H//I<0J=<0J<I00J=1K>=1K=J11K>2L?>2L>K22L?3M@?3M?L33M@4NA@4N@M44NAZ\[AZ\ANZ;bU<cVU<cUb<<cV=dWV=dVc==dW>eXW>eWd>>eX?fYX?fXe??fY@gZY@gYf@@gZAh[ZAhZgAAh[[^][[^[h[HobIpcbIpboIIpcJqdcJqcpJJqdKredKrdqKKreLsfeLserLLsfMtgfMtfsMMtgNuhgNugtNNuh\_^h\_hu\cI<b<I;bIH;bdJ=c=J<cJI<ceK>d>K=dKJ=dfL?e?L>eLK>egM@f@M?fML?fhNAgAN@gNM@g^\[h[\Ah\NAhU|V}|V|VV}W~}W}WW~X~X~XXYYYYZZZZ[[[[]a`]a]bccccddddeeeeffffgggghhhh^ba^b^oppppqqqqrrrrssssttttuuuu_cb_c_cVVcUcbUdWWdVdcVeXXeWedWfYYfXfeXgZZgYgfYh[[hZhgZa^]]^[^h[pccpbpobqddqcqpcreerdrqdsffsesretggtftsfuhhugutgb_^^_h_uh|}}}}~~~~`ed`e`afeafabgfbgbchgchc}}||~~}}~~ea``aafbaabbgcbbcc                   djidj d                                      ekj ek  e                                       flk fl  f%  &   &  % &  '   '  & '  (   (  ' (  )   )  ( )  *   *  ) *  +   +  * +  gml gm + g2 % 3 & % 3 % 2 3 & 4 ' & 4 & 3 4 ' 5 ( ' 5 ' 4 5 ( 6 ) ( 6 ( 5 6 ) 7 * ) 7 ) 6 7 * 8 + * 8 * 7 8 + hnm+ hn+ 8 h                 jed de e                       kfe ef f                         lgf fg g & % % % ' & & & ( ' ' ' ) ( ( ( * ) ) ) + * * * mhg+ gh+ h+ iii                   jjj                       kkk                         lll% & &  & & ' ' ' ' ( ( ( ( ) ) ) ) * * * * + + + + mmm2  3  3  3 3 4 4 4 4 5 5 5 5 6 6 6 6 7 7 7 7 8 8 8 8 nn n                  jiijj                                    kjjk k                                          lkkl l  &   &  & %  '   '  ' &  (   (  ( '  )   )  ) (  *   *  * )  +   +  + *  mllm m+  3 & & 3 % 3 2 % 4 ' ' 4 & 4 3 & 5 ( ( 5 ' 5 4 ' 6 ) ) 6 ( 6 5 ( 7 * * 7 ) 7 6 ) 8 + + 8 * 8 7 * nmmn+ n8 + .? H/@ IH/@ H? //@ I0A JI0A I@ 00A J1B KJ1B JA 11B K2C LK2C KB 22C L3D ML3D LC 33D M4E NM4E MD 44E NZo\NZoNE ZHL oIM poIM oL IIM pJN qpJN pM JJN qKO rqKO qN KKO rLP srLP rO LLP sMQ tsMQ sP MMQ tNR utNR tQ NNR u\p_u\puR \? Y L @ Z M L @ Z L Y @ @ Z M A [ N M A [ M Z A A [ N B \ O N B \ N [ B B \ O C ] P O C ] O \ C C ] P D ^ Q P D ^ P ] D D ^ Q E _ R Q E _ Q ^ E E _ R oqpR oqR _ oM @ IL I@ HL @ ? HL N A JM JA IM A @ IM O B KN KB JN B A JN P C LO LC KO C B KO Q D MP MD LP D C LP R E NQ NE MQ E D MQ po\R \oNR oE NR of pg pg f ppg qh qh g qqh ri ri h rri sj sj i ssj tk tk j ttk ul ul k uul _rc_rl _L s f M t g f M t f s M M t g N u h g N u g t N N u h O v i h O v h u O O v i P w j i P w i v P P w j Q x k j Q x j w Q Q x k R y l k R y k x R R y l psrl psl y pY s Z t s Z s Z Z t [ u t [ t [ [ u \ v u \ u \ \ v ] w v ] v ] ] w ^ x w ^ w ^ ^ x _ y x _ x _ _ y qtsy qty qg M pf pM of M L of h N qg qN pg N M pg i O rh rO qh O N qh j P si sP ri P O ri k Q tj tQ sj Q P sj l R uk uR tk R Q tk rp_l _pul pR ul t Z M s M Z L s Z Y L s u [ N t N [ M t [ Z M t v \ O u O \ N u \ [ N u w ] P v P ] O v ] \ O v x ^ Q w Q ^ P w ^ ] P w y _ R x R _ Q x _ ^ Q x sqpy pqR y q_ R y                          cuhcu cf g g g g h h h h i i i i j j j j k k k k l l l l rvu rv rs t t t t u u u u v v v v w w w w x x x x y y y y swv sw s txw tx t g  g  g f  h  h  h g  i  i  i h  j  j  j i  k  k  k j  l  l  l k  urc cr rl  t g g t f t s f u h h u g u t g v i i v h v u h w j j w i w v i x k k x j x w j y l l y k y x k vsr rsl sy l t t s s u u t t v v u u w w v v x x w w y y x x wts sty t y  2  3 2  2  3  4 3  3  4  5 4  4  5  6 5  5  6  7 6  6  7  8 7  7  8 hyn8 hy8 h uzy uz u v{z v{ v w|{ w| w x}| x} x                         yuh hu u  zvu uv v {wv vw w |xw wx x 2 3 3 3 3 4 4 4 4 5 5 5 5 6 6 6 6 7 7 7 7 8  8 8 8  n n n                   yyy                    zz z                         {  {  {        ! !  ! " "! " # #" # $ $# $|  | $| + , ,+ , -  -, -  .!  . - .! /"! /!. /" 0#" 0"/ 0# 1$# 1#0 1$}  $} $1} 3 3 2  2  4 4 3  3  5 5 4  4  6 6 5  5  7 7 6  6  8 8 7  7 ynny8 y 8                   zyyz z                     {z z{ {                    |{{| |        !   " ! ! !# " " "$ # # # }|$|} $} $. ? / @ ? / ?  // @ 0 A @ 0 @  00 A 1 B A 1 A  11 B 2 C B 2 B  22 C 3 D C 3 C  33 D 4 E D 4 D  44 E Z~oE Z~E  Z?  Y @  Z Y @  Y  @ @  Z A  [ Z A  Z  A A  [ B  \ [ B  [  B B  \ C  ] \ C  \  C C  ] D  ^ ] D  ]  D D  ^ E  _ ^ E  ^  E E  _ oq_ o_  o                                                 !    !    !   "    "  !   "  ~ ~ " ~  @  @  ?    ?    A  A  @    @    B  B  A    A    C  C  B    B    D  D  C    C    E  E  D    D  ~o o~E  ~ E  Y ) Z * Z * ) Z Z * [ + [ + * [ [ + \ , \ , + \ \ , ] - ] - , ] ] - ^ . ^ . - ^ ^ . _ / _ / . _ _ / qt q / q 6 )  7 * )  7 ) 6   7 *  8 + *  8 * 7   8 +  9 , +  9 + 8   9 ,  : - ,  : , 9   : -  ; . -  ; - :   ; .  < / .  < . ;   < / / / <  C 6  D 7 6  D 6 C   D 7  E 8 7  E 7 D   E 8  F 9 8  F 8 E   F 9 G : 9 G 9 F G : ! H ; : ! H : G ! ! H ; " I < ; " I ; H " " I < < < I *  Z ) Z  Y )   Y ) +  [ * [  Z *   Z * ,  \ + \  [ +   [ + -  ] , ]  \ ,   \ , .  ^ - ^  ] -   ] - /  _ . _  ^ .   ^ . q/ q_ /  _ / 7   6    6    6 8   7    7    7 9   8    8    8 :  9   9   9 ; !  :  !  : !  : < "  ;  "  ; " !  ; <  < "  < P Q Q P Q R R Q R S S R S T T S T U U T U V V U V tx t V t) ] P * ^ Q P * ^ P ] * * ^ Q + _ R Q + _ Q ^ + + _ R , ` S R , ` R _ , , ` S - a T S - a S ` - - a T . b U T . b T a . . b U / c V U / c U b / / c V V V c 6 j ] 7 k ^ ] 7 k ] j 7 7 k ^ 8 l _ ^ 8 l ^ k 8 8 l _ 9 m ` _ 9 m _ l 9 9 m ` : n a ` : n ` m : : n a ; o b a ; o a n ; ; o b < p c b < p b o < < p c c c p C w j D x k j D x j w D D x k E y l k E y k x E E y l F z m l F z l y F F z m G { n m G { m z G G { n H | o n H | n { H H | o I } p o I } o | I I } p p p } Q * P * P * ) P R + Q + Q + * Q S , R , R , + R T - S - S - , S U . T . T . - T V / U / U / . U tV t V / V ^ 7 * ] * 7 ) ] 7 6 ) ] _ 8 + ^ + 8 * ^ 8 7 * ^ ` 9 , _ , 9 + _ 9 8 + _ a : - ` - : , ` : 9 , ` b ; . a . ; - a ; : - a c < / b / < . b < ; . b c / c < / c k D 7 j 7 D 6 j D C 6 j l E 8 k 8 E 7 k E D 7 k m F 9 l 9 F 8 l F E 8 l n G : m : G 9 m G F 9 m o H ; n ; H : n H G : n p I < o < I ; o I H ; o p < p I < p x} x xP Q Q Q Q R R R R S S S S T T T T U U U U V V V V   ] ^ ^ ^ ^ _ _ _ _ ` ` ` ` a a a a b b b b c c c c   j k k k k l l l l m m m m n n n n o o o o p p p p   w x x x x y y y y z z z z { { { { | | | | } } } }    Q Q Q P R R R Q S S S R T T T S U U U T V V V U x x V ^ Q Q ^ P ^ ] P _ R R _ Q _ ^ Q ` S S ` R ` _ R a T T a S a ` S b U U b T b a T c V V c U c b U  V c V k ^ ^ k ] k j ] l _ _ l ^ l k ^ m ` ` m _ m l _ n a a n ` n m ` o b b o a o n a p c c p b p o b  c p c x k k x j x w j y l l y k y x k z m m z l z y l { n n { m { z m | o o | n | { n } p p } o } | o  p } p + ,+ + , -, , - .- - . /. . / 0/ / 0 10 0 1} 1}1}                                                                " # #" # $ $# $ % %$ % & &% & ' '& ' ( (' (( /" 0#" 0"/ 0# 1$# 1#0 1$ 2%$ 2$1 2% 3&% 3%2 3& 4'& 4&3 4' 5(' 5'4 5(((5 </ =0/ =/< =0 >10 >0= >1 ?21 ?1> ?2 @32 @2? @3 A43 A3@ A4 B54 B4A B5 5 5B                  }}                                               # " " "$ # # #% $ $ $& % % %' & & &( ' ' '( ( (0 / / /1 0 0 02 1 1 13 2 2 24 3 3 35 4 4 45 5 5.  /   /  //  0   0  00  1   1  11  2   2  22  3   3  33  4   4  44  Z~ Z Z                                 !    !  " !  !   " ~" ~" ~                            ~ ~    C  D C  C   D  E D  D   E  F E  E   F G F F G ! H G ! G ! ! H " I H " H " " I I I                                ! ! " " ! !  "  "    C  w D  x w D  w  D D  x E  y x E  x  E E  y F  z y F  y  F F  z G  { z G  z  G G  { H  | { H  {  H H  | I  } | I  |  I I  } } }    !   !  !  "   "  ! "  #   #  " #  $   $  # $  %   %  $ %  &   &  % &    &  - . ! . - . ! / " ! / ! . / " 0 # " 0 " / 0 # 1 $ # 1 # 0 1 $ 2 % $ 2 $ 1 2 % 3 & % 3 % 2 3 & & & 3  : -  ; . -  ; - :   ; .  < / .  < . ;   < / = 0 / = / < = 0 > 1 0 > 0 = > 1 ? 2 1 ? 1 > ? 2 @ 3 2 @ 2 ? @ 3 3 3 @  D  D C  C   E  E D  D   F  F E  E   G  G F  F   H  H G  G   I  I H  H   I   I  ! " ! ! ! # " " " $ # # # % $ $ $ & % % % &  &  & .  -  -   - /  .  .   . 0 / /  / 1 0 0 0 2 1 1 1 3 2 2 2 3  3  3 w G x H x H G x x H y I y I H y y I z J z J I z z J { K { K J { { K | L | L K | | L } M } M L } } M   M  T G  U H G  U G T   U H  V I H  V H U   V I  W J I  W I V   W J  X K J  X J W   X K  Y L K  Y K X   Y L  Z M L  Z L Y   Z M M M Z  a T ! b U T ! b T a ! ! b U " c V U " c U b " " c V # d W V # d V c # # d W $ e X W $ e W d $ $ e X % f Y X % f X e % % f Y & g Z Y & g Y f & & g Z Z Z g - n a . o b a . o a n . . o b / p c b / p b o / / p c 0 q d c 0 q c p 0 0 q d 1 r e d 1 r d q 1 1 r e 2 s f e 2 s e r 2 2 s f 3 t g f 3 t f s 3 3 t g g g t : { n ; | o n ; | n { ; ; | o < } p o < } o | < < } p = ~ q p = ~ p } = = ~ q >  r q >  q ~ > >  r ? s r ? r  ? ? s @ t s @ s @ @ t t t H  x G x  w G   w G I  y H y  x H   x H J  z I z  y I   y I K  { J {  z J   z J L  | K |  { K   { K M  } L }  | L   | L M } M  } M U !  T  !  T !  T V "  U  "  U " !  U W #  V  #  V # "  V X $  W  $  W $ #  W Y %  X  %  X % $  X Z &  Y  &  Y & %  Y Z  Z &  Z b . ! a ! . a . - a c / " b " / ! b / . ! b d 0 # c # 0 " c 0 / " c e 1 $ d $ 1 # d 1 0 # d f 2 % e % 2 $ e 2 1 $ e g 3 & f & 3 % f 3 2 % f g & g 3 & g o ; . n . ; - n ; : - n p < / o / < . o < ; . o q = 0 p 0 = / p = < / p r > 1 q 1 > 0 q > = 0 q s ? 2 r 2 ? 1 r ? > 1 r t @ 3 s 3 @ 2 s @ ? 2 s t 3 t @ 3 t < =< <  = >= =  > ?> > ? @? ? @ A@ @ A BA A B0 B0BG  H   H  H H  I  I  I I J J J J K K K K L L L L M M M M 101T &U 'U '&U U 'V (V ('V V (W )W )(W W )X *X *)X X *Y +Y +*Y Y +Z ,Z ,+Z Z ,212,a 3&b 4'&b 4&3b b 4'c 5('c 5'4c c 5(d 6)(d 6(5d d 6)e 7*)e 7)6e e 7*f 8+*f 8*7f f 8+g 9,+g 9+8g g 9,32,3,9n @3o A43o A3@o o A4p B54p B4Ap p B5q C65q C5Bq q C6r D76r D6Cr r D7s E87s E7Ds s E8t F98t F8Et t F943949F{ M@| NA@| N@M| | NA} OBA} OAN} } OB~ PCB~ PBO~ ~ PC QDC QCP  QD RED RDQ RE SFE SER SF54F5FS H  H H G I  I I H J  J J I K  K K J L  L L K M  M M L 0 M U H H U G U T G V I I V H V U H W J J W I W V I X K K X J X W J Y L L Y K Y X K Z M M Z L Z Y L 1M Z M 'b U &U b T &b a T &(c V 'V c U 'c b U ')d W (W d V (d c V (*e X )X e W )e d W )+f Y *Y f X *f e X *,g Z +Z g Y +g f Y +2,Z ,g Z ,4o b 3b o a 3o n a 35p c 4c p b 4p o b 46q d 5d q c 5q p c 57r e 6e r d 6r q d 68s f 7f s e 7s r e 79t g 8g t f 8t s f 839g 9t g 9A| o @o | n @| { n @B} p Ap } o A} | o AC~ q Bq ~ p B~ } p BD r Cr  q C ~ q CE s Ds r D  r DF t Et s E s E4Ft F t F. / / // 0 0 00 1 1 11 2 2 22 3 3 33 4 4 44 Z Z Z                                     :  ; :  :   ;  < ;  ;   < = < < = > = = > ? > > ? @ ? ? @ @ @                                          : { ; | { ; { ; ; | < } | < | < < } = ~ } = } = = ~ >   ~ >  ~ > >   ?   ?    ? ?  @  @   @ @                                             $  %   %  $ %  &   &  % &  '   '  & '  (   (  ' (  )   )  ( )  *   *  ) *    *  1 $ 2 % $ 2 $ 1 2 % 3 & % 3 % 2 3 & 4 ' & 4 & 3 4 ' 5 ( ' 5 ' 4 5 ( 6 ) ( 6 ( 5 6 ) 7 * ) 7 ) 6 7 * * * 7  > 1 ? 2 1 ? 1 > ? 2 @ 3 2 @ 2 ? @ 3 A 4 3 A 3 @ A 4  B 5 4  B 4 A   B 5  C 6 5  C 5 B   C 6  D 7 6  D 6 C   D 7 7 7 D  ; ; : : < < ; ; = = < <  > > = =  ?  ? >  >   @  @ ?  ?   @   @                               % $ $ $ & % % % ' & & & ( ' ' ' ) ( ( ( * ) ) ) *  *  * 2 1 1 1 3 2 2 2 4 3 3 3 5  4  4  4 6  5  5   5 7  6  6   6 7  7  7 { M| NM| M| | N} ON} N} } O~ PO~ O~ ~ P !QP !P   !Q "RQ "Q! "R #SR #R" #SE5SES# * + +* + , ,+ , -  -, -  .!  . -  .! /"! /!.  /" 0#" 0"/  0#FE#F#0 7* 8+* 8*7  8+ 9,+ 9+8  9, :-, :,9  :- ;.- ;-:  ;. </. <.;  </ =0/ =/<  =0GF0G0=$ D7% E87% E7D% % E8& F98& F8E& & F9' G:9' G9F' ' G:( H;:( H:G( ( H;) I<;) I;H) ) I<* J=<* J<I* * J=HG=H=J1 QD2 RED2 RDQ2 2 RE3 SFE3 SER3 3 SF4 TGF4 TFS4 4 TG5 UHG5 UGT5 5 UH6 VIH6 VHU6 6 VI7 WJI7 WIV7 7 WJIHJIJW> ^Q? _RQ? _Q^? ? _R@ `SR@ `R_@ @ `SA aTSA aS`A A aTB bUTB bTaB B bUC cVUC cUbC C cVD dWVD dVcD D dWJIWJWd | | {  {  } } |  |   ~ ~ }  } !    ~  ~ " !   !   !# "  "  "E# # #+ *  *  *, +  +  +- ,  ,  ,.  -  -  -/  .   .   .0  /   /   /F0 0  08%  7 %  7% $  79&  8 &  8& %  8:'  9 '  9' &  9;(  : (  :( '  :<)  ; )  ;) (  ;=*  < *  <* )  <G= =*  =E2 % D% 2 $ D2 1 $ DF3 & E& 3 % E3 2 % EG4 ' F' 4 & F4 3 & FH5 ( G( 5 ' G5 4 ' GI6 ) H) 6 ( H6 5 ( HJ7 * I* 7 ) I7 6 ) IHJ* J7 * JR? 2 Q2 ? 1 Q? > 1 QS@ 3 R3 @ 2 R@ ? 2 RTA 4 S4 A 3 SA @ 3 SUB 5 T5 B 4 TB A 4 TVC 6 U6 C 5 UC B 5 UWD 7 V7 D 6 VD C 6 VIW7 WD 7 W.; /< /< ;//< 0= 0= <00= 1> 1> =11> 2? 2? >22? 3@ 3@ ?33@ 4A 4A @44A Z[ Z[ AZ K L L K L M M L M N N M N O O N O P P O P Q Q P Q   Q ;UK <VL K <VK U<<VL =WM L =WL V==WM >XN M >XM W>>XN ?YO N ?YN X??YO @ZP O @ZO Y@@ZP A[Q P A[P ZAA[Q []Q []Q [[L < K < K <; K M = L = L =< L N > M > M >= M O ? N ? N ?> N P @ O @ O @? O Q A P A P A@ P [Q [ Q [A Q X Y Y X Y Z Z Y Z [ [ Z [ \ \ [ \ ] ] \ ] ^ ^ ] ^   ^ K e X L f Y X L f X e L L f Y M g Z Y M g Y f M M g Z N h [ Z N h Z g N N h [ O i \ [ O i [ h O O i \ P j ] \ P j \ i P P j ] Q k ^ ] Q k ] j Q Q k ^ ^ ^ k U|e V}f e V}e |VV}f W~g f W~f }WW~g Xh g Xg ~XXh Yi h Yh YYi Zj i Zi ZZj [k j [j [[k ]`k ]`k ]Y L X L X L K X Z M Y M Y M L Y [ N Z N Z N M Z \ O [ O [ O N [ ] P \ P \ P O \ ^ Q ] Q ] Q P ] ^  ^ Q ^ f VL e L VK e VUK e g WM f M WL f WVL f h XN g N XM g XWM g i YO h O YN h YXN h j ZP i P ZO i ZYO i k [Q j Q [P j [ZP j ]k ]Q k ][Q k r s s r s t t s t u u t u v  v u v  w   w  v w  x   x  w x    x X  r Y s r Y r  Y Y s Z t s Z s Z Z t [ u t [ t [ [ u \ v u \ u \ \ v ] w v ] v ] ] w ^ x w ^ w ^ ^ x x x e  f  f  f f g g g g h h h h i i i i j j j j k k k k   | } } }} ~ ~ ~~             `d `d `s Y r Y r Y X r t Z s Z s Z Y s u [ t [ t [ Z t v \ u \ u \ [ u w ] v ] v ] \ v x ^ w ^ w ^ ] w x  x ^ x f Y  Y f X  f e X  g Z Z g Y g f Y h [ [ h Z h g Z i \ \ i [ i h [ j ] ] j \ j i \ k ^ ^ k ] k j ]  ^ k ^ }f f }e }|e ~g g ~f ~}f h h g ~g i i h h j j i i k k j j ` `k `k > ? > > ? @ ? ? @ A @ @ A  B A  A   B  C B  B   C  D C  C   D D D r s s s s t t t t u u u u v v v v w w w w x x x x                            di di d s s s r t t t s u u u t v   v v u w   w  w v  x   x  x w    x  s s r  r t t s s u u t t v v u u w w v v x x w w  x  x                        d d d > ^? _^? ^? ? _@ `_@ _@ @ `A a`A `A A aB baB aB B bC cbC bC C cD dcD cD D dUJdUd                   VUV                       WVW                                      XW X  ! " "! " # #" # $ $# $ % %$ % & &% & ' '& 'YXY'!"!!"#""#$##$%$$%&%%&'&&'iY'i'i ? ? >  >  @ @ ?  ?  A A @  @  B B A  A  C C B  B  D D C  C UD  D                   V                         W                     X  " !  ! !# "  " "$ #  # #% $  $ $& %  % %' &  & &Yi'i 'i ' l     !!""# **++,, - -!.!."/"/#0   !!""# 7D7D8E8E9F9F:G:G;H;H<I<I =J DQDQERERFSFSGTGTHUHUIVIVJW Q^Q^R_R_S`S` Ta Ta!Ub!Ub"Vc"Vc#Wd *^k*^k+_l+_l,`m,`m-an-an.bo.bo/cp/cp0dq DDEEFFGGHHIIJ  QQRRSST T U!U!V"V"W# ^*^*_+_+`,`,a- a- b.!b.!c/"c/"d0# 7x7x8y8y9z9z:{:{;|;|<}<}=~ DDEEFFGGHHIIJ QQRRSSTTUUVVW^^__``aabbccdkkllmmnnooppq D7D7E8E8F9F9G:G:H;H;I<I<J= QDQDRERESFSFTGTGUHUHVIVIWJ ^Q^Q_R_R`S`SaTaTbUbUcVcVdWk^k^l_l_m`m`nanaobobpcpcqdxxyyzz{{||}}~                  xxyyzz{{||}}~         !!""##$$%%&&'..//001122334!.;!.;"/<"/<#0=#0=$1>$1>%2?%2?&3@&3@'4A.!.!/"/"0#0#1$1$2%2%3&3&4' *H*H+I+I,J,J-K-K.L.L/M/M0N !.HU.HU/IV/IV0JW0JW1KX1KX2LY2LY3MZ3MZ4N[!";Ub;Ub<Vc<Vc=Wd=Wd>Xe>Xe?Yf?Yf@Zg@ZgA[h H.H.I/I/J0J0K1K1L2L2M3M3N4!U;.U;.V</V</W=0W=0X>1X>1Y?2Y?2Z@3Z@3[A4 #*ko*ko+lp+lp,mq,mq-nr-nr.os.os/pt/pt0qu #$Ho|Ho|Ip}Ip}Jq~Jq~KrKrLsLsMtMtNu!$%U|U|V}V}W~W~XXYYZZ["%&bbccddeeffggh# oH*oH*pI+pI+qJ,qJ,rK-rK-sL.sL.tM/tM/uN0$! |UH|UH}VI}VI~WJ~WJXKXKYLYLZMZM[N%"!bUbUcVcVdWdWeXeXfYfYgZgZh['kkllmmnnooppq#'(ooppqqrrssttu$()||}}~~%)*&*+'#okokplplqmqmrnrnsosotptpuq($#|o|o}p}p~q~qrrssttu)%$||}}~~*&%,',-(-.)./      */0      +01%%&&''(())**+,'-('.)(/*)      0+*2!2!2"3"3#4#4$5$5%6%6&7&7'83!;?!;?"<@"<@#=A#=A$>B$>B%?C%?C&@D&@D'AE2342?L2?L3@M3@M4AN4AN5BO5BO6CP6CP7DQ7DQ8ER32?2!?2!@3"@3"A4#A4#B5$B5$C6%C6%D7&D7&E8'"5;bY;bY<cZ<cZ=d[=d[>e\>e\?f]?f]@g^@g^Ah_356?Yf?Yf@Zg@ZgA[hA[hB\iB\iC]jC]jD^kD^kE_l467LfsLfsMgtMgtNhuNhuOivOivPjwPjwQkxQkxRly53Y?;Y?;Z@<Z@<[A=[A=\B>\B>]C?]C?^D@^D@_EA643fL?fL?gM@gM@hNAhNAiOBiOBjPCjPCkQDkQDlRE"&8bbccddeeffggh589YYZZ[[\\]]^^_69:ffgghhiijjkkl7:;ssttuuvvwwxxy85"YbYbZcZc[d[d\e\e]f]f^g^g_h965fYfYgZgZh[h[i\i\j]j]k^k^l_:76sfsftgtguhuhviviwjwjxkxkyl&+<8<=9=>:>?;?@<8&=98>:9?;:+1A%%&&''(())**+<AB=BC>CD  !!"?DE))**++,, - -!.!."/@EF)6)6*7*7+8+8,9,9-:-:.;.;/<A<+B=<C>=D?>  !!"E@?))**++,,--../2G2C2C3D3D4E4E5F5F6G6G7H7H8I24H2LP2LP3MQ3MQ4NR4NR5OS5OS6PT6PT7QU7QU8RVGHICP]CP]DQ^DQ^ER_ER_FS`FS`GTaGTaHUbHUbIVcHG2PC2PC2QD3QD3RE4RE4SF5SF5TG6TG6UH7UH7VI847JLsjLsjMtkMtkNulNulOvmOvmPwnPwnQxoQxoRypHJKPjwPjwQkxQkxRlyRlySmzSmzTn{Tn{Uo|Uo|Vp}IKL]w]w^x^x_y_y`z`za{a{b|b|c}JH4jPLjPLkQMkQMlRNlRNmSOmSOnTPnTPoUQoUQpVRKIHw]Pw]Px^Qx^Qy_Ry_Rz`Sz`S{aT{aT|bU|bU}cV7;MssttuuvvwwxxyJMNjjkkllmmnnoopKNOwwxxyyzz{{||}LOPMJ7jsjsktktlulumvmvnwnwoxoxpyNKJwjwjxkxkylylzmzm{n{n|o|o}pOLKwwxxyyzz{{||};@QMQRNRSOSTPTUQM;RNMSONTPO@FV6677889 9 : : ; ; < QVW       RWX  !!""##$$%%&SXY - -!.!."/"/#0#0$1$1%2%2&3TYZ-:-:.;.;/</<0=0=1>1>2?2?3@UZ[:G:G;H;H<I<I=J=J>K>K?L?L@MVQ@       WRQXSR  !!""##$$%%&YTS--..//0011223ZUT::;;<<==>>??@G\CTCTDUDUEVEVFWFWGXGXHYHYIZGI]C]aC]aD^bD^bE_cE_cF`dF`dGaeGaeHbfHbfIcg\]^TanTanUboUboVcpVcpWdqWdqXerXerYfsYfsZgt]\GaTCaTCbUDbUDcVEcVEdWFdWFeXGeXGfYHfYHgZIIL_]{]{^|^|_}_}`~`~aabbc]_`a{a{b|b|c}c}d~d~eeffg^`annooppqqrrsst_]I{a]{a]|b^|b^}c_}c_~d`~d`eaeafbfbgc`^]nanaobobpcpcqdqdreresfsftgLPb_bc{{||}}~~`cdadeb_L{{||}}~~c`_{{||}}~~da`PUfbfgcghdhieij        fbPgcbhdciedU[kGGHHIIJJKKLLMfkl$$%%&&''(())*glm$1$1%2%2&3&3'4'4(5(5)6)6*7hmn1>1>2?2?3@3@4A4A5B5B6C6C7Dino>K>K?L?L@M@MANANBOBOCPCPDQjop KX KX LY LY MZ MZ N[ N[O\O\P]P]Q^kfUlgf$$%%&&''(())*mhg1122334455667nih>>??@@AABBCCDojiK K L L M M N N OOPPQ\TTUUVVWWXXYYZ\^qTneTneUofUofVpgVpgWqhWqhXriXriYsjYsjZtkqeeffgghhiijjkq\eTeTfUfUgVgVhWhWiXiXjYjYkZ^arnrnrososptptququrvrvswswtxqrsererfsfsgtgthuhuivivjwjwkxs rq^renrensfosfotgptgpuhquhqvirvirwjswjsxktsqeeffgghhiijjkaetrturrssttuuvvwwxsuvv 778899::;;<< =trarrssttuuvvwwxusrrrssttuuvvwwxvs ejw        twxuxyvyz z7x7x8y8y9z9z:{:{;|;|<}<}=~wtexutyvuz v778899::;;<<=jp{ X X Y Y Z Z [ [\\]]^w{|x|}y}~z~  !xxyyzz{{||} } ~!{wj        |xw}yx~zyzxxyyzz{{|| } }!~(B5(B5)C6)C6*D7*D7+E8+E8,F9,F9-G:-G:.H;5\O5\O6]P6]P7^Q7^Q8_R8_R9`S9`S:aT:aT;bUBi\Bi\Cj]Cj]Dk^Dk^El_El_Fm`Fm`GnaGnaHob\5B\5B]6C]6C^7D^7D_8E_8E`9F`9Fa:Ga:Gb;HOvOvPwPwQxQxRyRySzSzT{T{U|\\]]^^__``aabiijjkkllmmnnoO\O\P]P]Q^Q^R_R_S`S`TaTaUb\i\i]j]j^k^k_l_l`m`mananbovvwwxxyyzz{{|vvwwxxyyzz{{|                                          !  !  "  "  #  #  $  $  %  ,  ,  - - . ! . ! / " / " 0 # 0 # 1 $ 1 $ 2 %                               ! ! " " # # $ $ %                               ! ! " " # # $ $ % , , - - .  .  /  /  0  0  1  1  2                                                !  !  "  "  #  #  $  $  %  ,  ,  -  - ! . ! . " / " / # 0 # 0 $ 1 $ 1 % 2 (9 B(9 B): C): C*; D*; D+< E+< E,= F,= F-> G-> G.? HBF iBF iCG jCG jDH kDH kEI lEI lFJ mFJ mGK nGK nHL o9 S F 9 S F : T G : T G ; U H ; U H < V I < V I = W J = W J > X K > X K ? Y L F B9 F B9 G C: G C: H D; H D; I E< I E< J F= J F= K G> K G> L H? i` i` ja ja kb kb lc lc md md ne ne of F m ` F m ` G n a G n a H o b H o b I p c I p c J q d J q d K r e K r e L s f S z m S z m T { n T { n U | o U | o V } p V } p W ~ q W ~ q X  r X  r Y s ` iF ` iF a jG a jG b kH b kH c lI c lI d mJ d mJ e nK e nK f oL m F S m F S n G T n G T o H U o H U p I V p I V q J W q J W r K X r K X s L Y              ` ` a a b b c c d d e e f m m n n o o p p q q r r s z z { { | | } } ~ ~   ` ` a a b b c c d d e e f ` m ` m a n a n b o b o c p c p d q d q e r e r f s m z m z n { n { o | o | p } p } q ~ q ~ r  r  s  ,  ,  -  -  .  .  /  /  0  0  1  1  2              ,, , - - . . / / 0 0 1 1 2 -,             .-             /.             0/                   10 % % & & ' ' ( ( ) ) * * +,, , - - . . / / 0 0 1 1 2 -             .             /              0             ( 9 ( 9 ) : ) : * ; * ; + < + < , = , = - > - > . ? 9 S 9 S : T : T ; U ; U < V < V = W = W >  X >  X ?  Y                    9 9 : : ; ; < < = =  >   >   ?  S # z S # z T $ { T $ { U % | U % | V & } V & } W ' ~ W ' ~ X (  X (  Y ) 0 # 0 # 1 $ 1 $ 2 % 2 % 3 & 3 & 4 ' 4 '  5 (  5 (  6 )  = 0  = 0  > 1  > 1  ? 2  ? 2  @ 3  @ 3  A 4  A 4  B 5  B 5  C 6 # S # S $ T $ T % U % U & V & V ' W ' W ( X  ( X  ) Y  0  0  1  1  2  2  3  3  4  4  5   5   6   z J z J { K { K | L | L } M } M ~ N ~ N  O  O P # W J # W J $ X K $ X K % Y L % Y L & Z M & Z M ' [ N ' [ N ( \ O ( \ O ) ] P 0 d W 0 d W 1 e X 1 e X 2 f Y 2 f Y 3 g Z 3 g Z 4 h [ 4 h [ 5 i \ 5 i \ 6 j ] = q d = q d > r e > r e ? s f ? s f @ t g @ t g A u h A u h B v i B v i C w j J z # J z # K { $ K { $ L | % L | % M } & M } & N ~ ' N ~ ' O  ( O  ( P ) W # 0 W # 0 X $ 1 X $ 1 Y % 2 Y % 2 Z & 3 Z & 3 [ ' 4 [ ' 4 \ ( 5 \ ( 5 ] ) 6 d 0 = d 0 = e 1 > e 1 > f 2 ? f 2 ? g 3 @ g 3 @ h 4 A h 4 A i 5 B i 5 B j 6 C ~ ~   J ~ J ~ K  K  L L M M N N O O P W W X X Y Y Z Z [ [ \ \ ] d d e e f f g g h h i i j q q r r s s t t u u v v w ~ J ~ J  K  K L L M M N N O O P J W J W K X K X L Y L Y M Z M Z N [ N [ O \ O \ P ] W d W d X e X e Y f Y f Z g Z g [ h [ h \ i \ i ] j d q d q e r e r f s f s g t g t h u h u i v i v j w A1 % % & & ' ' ( ( ) ) * * +BA~ ~            CB             DC           ! ! "ED ) ) * * + + , , -  -  .! .! /"FE 6) 6) 7* 7* 8+ 8+ 9, 9, :- :- ;. ;. </A ~  ~              B~ ~            C             D          ! ! " E) ) * * + + , , - - . . / ( ( ) ) * * + + , , -  -  .                      =  =  >  >  ?  ?  @  @  A  A  B  B  C                         = q = q >  r >  r ?  s ?  s @  t @  t A  u A  u B  v B  v C  w                        '  '  (  (  )  )  *  *  +  +  ,  ,  - 4 ' 4 '  5 (  5 (  6 )  6 )  7 *  7 *  8 +  8 +  9 ,  9 ,  : - = =  >  >  ?  ?  @  @  A  A  B  B  C             ' ' (  (  )  )  *  *  +  +  ,  ,  -  q A q A r B r B s C s C t D t D u E u E v F v F w G N A N A  O B  O B  P C  P C  Q D  Q D  R E  R E  S F  S F  T G  [ N  [ N  \ O  \ O  ] P  ] P  ^ Q  ^ Q  _ R  _ R  ` S  ` S a T ' h [ ' h [ ( i \ ( i \ ) j ] ) j ] * k ^ * k ^ + l _ + l _ , m ` , m ` - n a 4 u h 4 u h 5 v i 5 v i 6 w j 6 w j 7 x k 7 x k 8 y l 8 y l 9 z m 9 z m : { n A q A q B r  B r  C s  C s  D t  D t  E u  E u  F v  F v  G w  N  N  O   O   P   P   Q   Q   R   R   S   S   T  [  ' [  ' \  ( \  ( ]  ) ]  ) ^  * ^  * _  + _  + `  , `  , a - h ' 4 h ' 4 i ( 5 i ( 5 j ) 6 j ) 6 k * 7 k * 7 l + 8 l + 8 m , 9 m , 9 n - : VF 6 6 7 7 8 8 9 9 : : ; ; <WVA A B B C C D  D  E  E  F  F  G  XWN N O !O !P "P "Q #Q #R $R $S %S %T &YX[ - [ - \ .!\ .!] /"] /"^ 0#^ 0#_ 1$_ 1$` 2%` 2%a 3&ZYh :-h :-i ;.i ;.j </j </k =0k =0l >1l >1m ?2m ?2n @3[Zu G:u G:v H;v H;w I<w I<x J=x J=y K>y K>z L?z L?{ M@V A  A  B  B  C  C  D  D  E  E  F  F  G WA N A N B O B O C P C P D Q D Q E R E R F S F S G T X N [ N [ !O \ !O \ "P ] "P ] #Q ^ #Q ^ $R _ $R _ %S ` %S ` &T a Y-[ h -[ h .\ i .\ i /] j /] j 0^ k 0^ k 1_ l 1_ l 2` m 2` m 3a n Z:h u :h u ;i v ;i v <j w <j w =k x =k x >l y >l y ?m z ?m z @n { ( ( ) ) * * + + , , - - .            4 4  5  5  6  6  7  7  8  8  9  9  :            4  u 4  u 5  v 5  v 6  w 6  w 7  x 7  x 8  y 8  y 9 z 9 z : {                                  !  !  "  "  #  #  $  +  +  ,  ,  - - . ! . ! / " / " 0 # 0 # 1 $ 8 + 8 + 9 , 9 , : - : - ; . ; . < / < / = 0 = 0 > 1  4  4  5  5  6  6  7  7  8  8 9 9 :                  ! ! " " # # $ + + , , - - . . / / 0 0 1 k[u Gu Gv Hv Hw Iw Ix Jx Jy Ky Kz Lz L{ Mlk $ $ % % & & ' ' ( ( ) ) *ml 1$ 1$ 2% 2% 3& 3& 4' 4' 5( 5( 6) 6) 7*nm >1 >1 ?2 ?2 @3 @3! A4! A4" B5" B5# C6# C6$ D7on+ K>+ K>, L?, L?- M@- M@. NA. NA/ OB/ OB0 PC0 PC1 QDpo8 XK8 XK9 YL9 YL: ZM: ZM; [N; [N< \O< \O= ]P= ]P> ^Qku  u  v  v  w  w  x  x  y  y  z z { l$  $  %  %  &  &  '  '  (  (  )  )  *  m1  1  2  2  3 3 4 ! 4 ! 5 " 5 " 6 # 6 # 7 $ n> + > + ? , ? , @ - @ - A! . A! . B" / B" / C# 0 C# 0 D$ 1 oK+ 8 K+ 8 L, 9 L, 9 M- : M- : N. ; N. ; O/ < O/ < P0 = P0 = Q1 > (5 (5 )6 )6 *7 *7 +8 +8 ,9 ,9 -: -: .; E E F F G G H H I I J J K 5OE 5OE 6PF 6PF 7QG 7QG 8RH 8RH 9SI 9SI :TJ :TJ ;UK E 5E 5F 6F 6G 7G 7H 8H 8I 9I 9J :J :K ; R R S S T T U U V V W W X E _ R E _ R F ` S F ` S G a T G a T H b U H b U I c V I c V J d W J d W K e X Ov_ Ov_ Pw` Pw` Qxa Qxa Ryb Ryb Szc Szc T{d T{d U|e R E R E S F S F T G T G U H U H V I V I W J W J X K _ E O_ E O` F P` F Pa G Qa G Qb H Rb H Rc I Sc I Sd J Td J Te K U l l m m n n o o p p q q r R y l R y l S z m S z m T { n T { n U | o U | o V } p V } p W ~ q W ~ q X  r _ y _ y ` z ` z a { a { b | b | c } c } d ~ d ~ e  v v w w x x y y z z { { | l R l R m S m S n T n T o U o U p V p V q W q W r X y R _ y R _ z S ` z S ` { T a { T a | U b | U b } V c } V c ~ W d ~ W d  X e _ v _ v ` w ` w a x a x b y b y c z c z d { d { e | 8 8 9 9 : : ; ; < < = = > l l m m n n o o p p q q r y y z z { { | | } } ~ ~               l l m m n n o o p p q q r l y l y m z m z n { n { o | o | p } p } q ~ q ~ r  y y z z { { | | } } ~ ~              {p8 X8 X9 Y9 Y: Z: Z; [; [< \< \= ]= ]> ^|{             }|             ~}             ~             !  !{8 8 9 9 : : ; ; < < = = > |             }             ~                           ! 6tests/meshes/msh/000077500000000000000000000000001456244072500143045ustar00rootroot00000000000000tests/meshes/msh/Makefile000066400000000000000000000001741456244072500157460ustar00rootroot00000000000000%-2.2.msh: %.geo gmsh -2 -format msh2 -o $@ $< %-4.1.msh: %.geo gmsh -2 -o $@ $< all: insulated-2.2.msh insulated-4.1.msh tests/meshes/msh/README.md000066400000000000000000000007751456244072500155740ustar00rootroot00000000000000Two versions of the Gmsh MSH format are covered here: 2.2 and 4.1. The meshes were generated by Gmsh 4.2.2-git-0766f664d from the same Gmsh GEO file `insulated.geo` as shown in the `Makefile` (`make -j2`); the difference is that the first was passed `-format msh2`, MSH4.1 being the default. The meshes are coarse versions of a real finite element example and contain 111 3-node triangular domain elements, divided into two Physical Surfaces, and 21 2-node line boundary elements, in a single Physical Line.tests/meshes/msh/insulated-2.2.msh000066400000000000000000000125471456244072500173150ustar00rootroot00000000000000$MeshFormat 2.2 0 8 $EndMeshFormat $PhysicalNames 3 1 3 "convection" 2 1 "wire" 2 2 "insulation" $EndPhysicalNames $Nodes 67 1 2 0 0 2 -0.9999999999999996 1.732050807568877 0 3 -1.000000000000001 -1.732050807568877 0 4 3 0 0 5 -1.499999999999999 2.598076211353316 0 6 -1.500000000000001 -2.598076211353315 0 7 1.827090914409903 0.8134732881175547 0 8 1.338261209269959 1.486289654059163 0 9 0.6180339846184854 1.902113033932683 0 10 -0.2090569285631289 1.989043790523414 0 11 -1.618033990162066 1.17557050264126 0 12 -1.95629520245368 0.4158233769964312 0 13 -1.956295200503979 -0.4158233861690545 0 14 -1.618033987472603 -1.175570506342989 0 15 -0.2090569245005841 -1.989043790950405 0 16 0.6180339927037 -1.902113031305638 0 17 1.33826121597086 -1.486289648025645 0 18 1.827090916184073 -0.8134732841327028 0 19 2.866718416712208 0.884265525327689 0 20 2.478716320112386 1.689960178349925 0 21 1.870469399717563 2.345494452076197 0 22 1.096023066394168 2.792621248564138 0 23 0.2241902761490784 2.991611391889027 0 24 -0.6675628038033028 2.924783736103966 0 25 -2.19915561691068 2.040518211781069 0 26 -2.70290660585828 1.301651212886028 0 27 -2.96649247971263 0.4471267916468595 0 28 -2.966492477661765 -0.447126805253458 0 29 -2.702906601876784 -1.301651221153692 0 30 -2.199155614492735 -2.040518214386993 0 31 -0.667562799591218 -2.924783737065347 0 32 0.2241902856922546 -2.991611391173865 0 33 1.096023079844227 -2.792621243285379 0 34 1.870469411104438 -2.345494442995467 0 35 2.478716325782583 -1.689960170033273 0 36 2.866718418080356 -0.8842655208922591 0 37 -0.9339546057726886 -0.4158233831706852 0 38 0.02141496984582745 1.058980690221818 0 39 -0.1941278312183717 0.1071477189577097 0 40 0.9834805227413372 0.6826480240423473 0 41 -0.7686480115959173 0.5453804900735302 0 42 0.9999999999999992 -0.2125565610925706 0 43 0.1213651863888595 -1.154712599348981 0 44 -0.6406278644518437 -1.11916553237733 0 45 0.8593162093855847 -0.9615150557898803 0 46 -0.5943735880144831 1.234440025041052 0 47 -1.335215615779825 0.1351111195641902 0 48 0.6825711700739076 1.215293176376306 0 49 1.45264285928781 0.3208911877668328 0 50 0.3069952762974677 -0.3818091452905251 0 51 -0.2680699677513154 -0.5928725882459622 0 52 0.3727472045845057 0.474808656902285 0 53 1.237382076390581 -2.143208614122736 0 54 -2.474764143942451 -5.801802924119936e-09 0 55 -0.7488578504306679 2.3047474739574 0 56 1.237382067086159 2.143208619683771 0 57 -1.621540936588582 -1.800903659450643 0 58 -1.621540937918335 1.800903656784694 0 59 2.37039878696343 -0.5038438145749483 0 60 -2.187495154555313 -1.033152983087325 0 61 0.1990108480843664 2.411002866027006 0 62 1.988484306593702 -1.377849882960454 0 63 -2.187495156981738 1.033152975378704 0 64 1.988484301214432 1.377849888762947 0 65 0.1990108553729037 -2.411002864348951 0 66 -0.7488578478505082 -2.304747474025119 0 67 2.370398785654296 0.5038438169983678 0 $EndNodes $Elements 132 1 1 2 3 4 4 19 2 1 2 3 4 19 20 3 1 2 3 4 20 21 4 1 2 3 4 21 22 5 1 2 3 4 22 23 6 1 2 3 4 23 24 7 1 2 3 4 24 5 8 1 2 3 5 5 25 9 1 2 3 5 25 26 10 1 2 3 5 26 27 11 1 2 3 5 27 28 12 1 2 3 5 28 29 13 1 2 3 5 29 30 14 1 2 3 5 30 6 15 1 2 3 6 6 31 16 1 2 3 6 31 32 17 1 2 3 6 32 33 18 1 2 3 6 33 34 19 1 2 3 6 34 35 20 1 2 3 6 35 36 21 1 2 3 6 36 4 22 2 2 1 1 39 38 41 23 2 2 1 1 37 39 41 24 2 2 1 1 38 39 52 25 2 2 1 1 13 14 37 26 2 2 1 1 9 10 38 27 2 2 1 1 18 1 42 28 2 2 1 1 15 16 43 29 2 2 1 1 41 11 47 30 2 2 1 1 11 41 46 31 2 2 1 1 37 14 44 32 2 2 1 1 18 42 45 33 2 2 1 1 43 16 45 34 2 2 1 1 15 43 44 35 2 2 1 1 11 12 47 36 2 2 1 1 39 37 51 37 2 2 1 1 9 38 48 38 2 2 1 1 42 1 49 39 2 2 1 1 2 11 46 40 2 2 1 1 38 10 46 41 2 2 1 1 41 38 46 42 2 2 1 1 13 37 47 43 2 2 1 1 14 3 44 44 2 2 1 1 17 18 45 45 2 2 1 1 3 15 44 46 2 2 1 1 16 17 45 47 2 2 1 1 7 8 40 48 2 2 1 1 37 41 47 49 2 2 1 1 50 42 52 50 2 2 1 1 42 40 52 51 2 2 1 1 39 50 52 52 2 2 1 1 10 2 46 53 2 2 1 1 12 13 47 54 2 2 1 1 40 8 48 55 2 2 1 1 7 40 49 56 2 2 1 1 40 42 49 57 2 2 1 1 48 38 52 58 2 2 1 1 40 48 52 59 2 2 1 1 1 7 49 60 2 2 1 1 8 9 48 61 2 2 1 1 43 50 51 62 2 2 1 1 50 39 51 63 2 2 1 1 44 43 51 64 2 2 1 1 43 45 50 65 2 2 1 1 37 44 51 66 2 2 1 1 45 42 50 67 2 2 2 2 58 25 63 68 2 2 2 2 36 59 62 69 2 2 2 2 24 55 61 70 2 2 2 2 67 19 64 71 2 2 2 2 30 57 60 72 2 2 2 2 66 31 65 73 2 2 2 2 11 58 63 74 2 2 2 2 7 67 64 75 2 2 2 2 15 66 65 76 2 2 2 2 55 10 61 77 2 2 2 2 59 18 62 78 2 2 2 2 57 14 60 79 2 2 2 2 35 36 62 80 2 2 2 2 23 24 61 81 2 2 2 2 25 26 63 82 2 2 2 2 29 30 60 83 2 2 2 2 19 20 64 84 2 2 2 2 31 32 65 85 2 2 2 2 13 28 60 86 2 2 2 2 9 22 61 87 2 2 2 2 17 34 62 88 2 2 2 2 21 8 64 89 2 2 2 2 33 16 65 90 2 2 2 2 27 12 63 91 2 2 2 2 28 13 54 92 2 2 2 2 22 9 56 93 2 2 2 2 34 17 53 94 2 2 2 2 8 21 56 95 2 2 2 2 16 33 53 96 2 2 2 2 12 27 54 97 2 2 2 2 4 1 59 98 2 2 2 2 5 2 55 99 2 2 2 2 6 3 57 100 2 2 2 2 1 4 67 101 2 2 2 2 2 5 58 102 2 2 2 2 3 6 66 103 2 2 2 2 28 29 60 104 2 2 2 2 20 21 64 105 2 2 2 2 32 33 65 106 2 2 2 2 34 35 62 107 2 2 2 2 22 23 61 108 2 2 2 2 26 27 63 109 2 2 2 2 4 19 67 110 2 2 2 2 5 25 58 111 2 2 2 2 6 31 66 112 2 2 2 2 30 6 57 113 2 2 2 2 24 5 55 114 2 2 2 2 36 4 59 115 2 2 2 2 27 28 54 116 2 2 2 2 21 22 56 117 2 2 2 2 33 34 53 118 2 2 2 2 13 12 54 119 2 2 2 2 17 16 53 120 2 2 2 2 9 8 56 121 2 2 2 2 11 2 58 122 2 2 2 2 7 1 67 123 2 2 2 2 15 3 66 124 2 2 2 2 3 14 57 125 2 2 2 2 2 10 55 126 2 2 2 2 1 18 59 127 2 2 2 2 8 7 64 128 2 2 2 2 12 11 63 129 2 2 2 2 16 15 65 130 2 2 2 2 18 17 62 131 2 2 2 2 10 9 61 132 2 2 2 2 14 13 60 $EndElements tests/meshes/msh/insulated-4.1.msh000066400000000000000000000127021456244072500173070ustar00rootroot00000000000000$MeshFormat 4.1 0 8 $EndMeshFormat $PhysicalNames 3 1 3 "convection" 2 1 "wire" 2 2 "insulation" $EndPhysicalNames $Entities 8 6 2 0 1 0 0 0 0 2 2 0 0 0 3 -0.9999999999999996 1.732050807568877 0 0 4 -1.000000000000001 -1.732050807568877 0 0 5 0 0 0 0 6 3 0 0 0 7 -1.499999999999999 2.598076211353316 0 0 8 -1.500000000000001 -2.598076211353315 0 0 1 -0.9999999999999996 0 0 2 1.996616316542536 0 0 2 2 -3 2 -1.986476715483886 -1.732050807568877 0 -1 1.732050807568878 0 0 2 3 -4 3 -1.000000000000001 -1.996616316542536 0 2 3.33066907387547e-16 0 0 2 4 -2 4 -1.499999999999999 0 0 3 2.994924474813804 0 1 3 2 6 -7 5 -2.97971507322583 -2.598076211353315 0 -1.5 2.598076211353317 0 1 3 2 7 -8 6 -1.500000000000002 -2.994924474813804 0 3 6.661338147750939e-16 0 1 3 2 8 -6 1 -1.986476715483886 -1.996616316542536 0 2 1.996616316542536 0 1 1 3 1 2 3 2 -2.97971507322583 -2.994924474813804 0 3 2.994924474813804 0 1 2 6 4 5 6 -3 -2 -1 $EndEntities $Nodes 14 67 1 67 0 2 0 1 1 2 0 0 0 3 0 1 2 -0.9999999999999996 1.732050807568877 0 0 4 0 1 3 -1.000000000000001 -1.732050807568877 0 0 6 0 1 4 3 0 0 0 7 0 1 5 -1.499999999999999 2.598076211353316 0 0 8 0 1 6 -1.500000000000001 -2.598076211353315 0 1 1 0 4 7 8 9 10 1.827090914409903 0.8134732881175547 0 1.338261209269959 1.486289654059163 0 0.6180339846184854 1.902113033932683 0 -0.2090569285631289 1.989043790523414 0 1 2 0 4 11 12 13 14 -1.618033990162066 1.17557050264126 0 -1.95629520245368 0.4158233769964312 0 -1.956295200503979 -0.4158233861690545 0 -1.618033987472603 -1.175570506342989 0 1 3 0 4 15 16 17 18 -0.2090569245005841 -1.989043790950405 0 0.6180339927037 -1.902113031305638 0 1.33826121597086 -1.486289648025645 0 1.827090916184073 -0.8134732841327028 0 1 4 0 6 19 20 21 22 23 24 2.866718416712208 0.884265525327689 0 2.478716320112386 1.689960178349925 0 1.870469399717563 2.345494452076197 0 1.096023066394168 2.792621248564138 0 0.2241902761490784 2.991611391889027 0 -0.6675628038033028 2.924783736103966 0 1 5 0 6 25 26 27 28 29 30 -2.19915561691068 2.040518211781069 0 -2.70290660585828 1.301651212886028 0 -2.96649247971263 0.4471267916468595 0 -2.966492477661765 -0.447126805253458 0 -2.702906601876784 -1.301651221153692 0 -2.199155614492735 -2.040518214386993 0 1 6 0 6 31 32 33 34 35 36 -0.667562799591218 -2.924783737065347 0 0.2241902856922546 -2.991611391173865 0 1.096023079844227 -2.792621243285379 0 1.870469411104438 -2.345494442995467 0 2.478716325782583 -1.689960170033273 0 2.866718418080356 -0.8842655208922591 0 2 1 0 16 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 -0.9339546057726886 -0.4158233831706852 0 0.02141496984582745 1.058980690221818 0 -0.1941278312183717 0.1071477189577097 0 0.9834805227413372 0.6826480240423473 0 -0.7686480115959173 0.5453804900735302 0 0.9999999999999992 -0.2125565610925706 0 0.1213651863888595 -1.154712599348981 0 -0.6406278644518437 -1.11916553237733 0 0.8593162093855847 -0.9615150557898803 0 -0.5943735880144831 1.234440025041052 0 -1.335215615779825 0.1351111195641902 0 0.6825711700739076 1.215293176376306 0 1.45264285928781 0.3208911877668328 0 0.3069952762974677 -0.3818091452905251 0 -0.2680699677513154 -0.5928725882459622 0 0.3727472045845057 0.474808656902285 0 2 2 0 15 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 1.237382076390581 -2.143208614122736 0 -2.474764143942451 -5.801802924119936e-09 0 -0.7488578504306679 2.3047474739574 0 1.237382067086159 2.143208619683771 0 -1.621540936588582 -1.800903659450643 0 -1.621540937918335 1.800903656784694 0 2.37039878696343 -0.5038438145749483 0 -2.187495154555313 -1.033152983087325 0 0.1990108480843664 2.411002866027006 0 1.988484306593702 -1.377849882960454 0 -2.187495156981738 1.033152975378704 0 1.988484301214432 1.377849888762947 0 0.1990108553729037 -2.411002864348951 0 -0.7488578478505082 -2.304747474025119 0 2.370398785654296 0.5038438169983678 0 $EndNodes $Elements 5 132 1 132 1 4 1 7 1 4 19 2 19 20 3 20 21 4 21 22 5 22 23 6 23 24 7 24 5 1 5 1 7 8 5 25 9 25 26 10 26 27 11 27 28 12 28 29 13 29 30 14 30 6 1 6 1 7 15 6 31 16 31 32 17 32 33 18 33 34 19 34 35 20 35 36 21 36 4 2 1 2 45 22 39 38 41 23 37 39 41 24 38 39 52 25 13 14 37 26 9 10 38 27 18 1 42 28 15 16 43 29 41 11 47 30 11 41 46 31 37 14 44 32 18 42 45 33 43 16 45 34 15 43 44 35 11 12 47 36 39 37 51 37 9 38 48 38 42 1 49 39 2 11 46 40 38 10 46 41 41 38 46 42 13 37 47 43 14 3 44 44 17 18 45 45 3 15 44 46 16 17 45 47 7 8 40 48 37 41 47 49 50 42 52 50 42 40 52 51 39 50 52 52 10 2 46 53 12 13 47 54 40 8 48 55 7 40 49 56 40 42 49 57 48 38 52 58 40 48 52 59 1 7 49 60 8 9 48 61 43 50 51 62 50 39 51 63 44 43 51 64 43 45 50 65 37 44 51 66 45 42 50 2 2 2 66 67 58 25 63 68 36 59 62 69 24 55 61 70 67 19 64 71 30 57 60 72 66 31 65 73 11 58 63 74 7 67 64 75 15 66 65 76 55 10 61 77 59 18 62 78 57 14 60 79 35 36 62 80 23 24 61 81 25 26 63 82 29 30 60 83 19 20 64 84 31 32 65 85 13 28 60 86 9 22 61 87 17 34 62 88 21 8 64 89 33 16 65 90 27 12 63 91 28 13 54 92 22 9 56 93 34 17 53 94 8 21 56 95 16 33 53 96 12 27 54 97 4 1 59 98 5 2 55 99 6 3 57 100 1 4 67 101 2 5 58 102 3 6 66 103 28 29 60 104 20 21 64 105 32 33 65 106 34 35 62 107 22 23 61 108 26 27 63 109 4 19 67 110 5 25 58 111 6 31 66 112 30 6 57 113 24 5 55 114 36 4 59 115 27 28 54 116 21 22 56 117 33 34 53 118 13 12 54 119 17 16 53 120 9 8 56 121 11 2 58 122 7 1 67 123 15 3 66 124 3 14 57 125 2 10 55 126 1 18 59 127 8 7 64 128 12 11 63 129 16 15 65 130 18 17 62 131 10 9 61 132 14 13 60 $EndElements tests/meshes/nastran/000077500000000000000000000000001456244072500151635ustar00rootroot00000000000000tests/meshes/nastran/README.md000066400000000000000000000002251456244072500164410ustar00rootroot00000000000000`cylinder.fem` is a HyperMesh-generated Optistruct (Nastran-like) mesh file. It contains the same mesh information as that in `../med/cylinder.med`. tests/meshes/nastran/cylinder.fem000066400000000000000000000270121456244072500174670ustar00rootroot00000000000000$$ $$ Optistruct Input Deck Generated by HyperMesh Version : 2017.3.0.17 $$ Generated using HyperMesh-Optistruct Template Version : 2017.3 $$ $$ Template: optistruct $$ $$ $$ optistruct $ $$------------------------------------------------------------------------------$ $$ Case Control Cards $ $$------------------------------------------------------------------------------$ $$-------------------------------------------------------------- $$ HYPERMESH TAGS $$-------------------------------------------------------------- $$BEGIN TAGS $$END TAGS $ BEGIN BULK $$ $$ Stacking Information for Ply-Based Composite Definition $$ $$ $$ GRID Data $$ GRID 1 1.0 -2.45-160.0 GRID 2 1.0 -2.45-161.0 GRID 3 .7071068.70710680.0 GRID 4 2.06-15 1.0 0.0 GRID 5 -.707107.70710680.0 GRID 6 -1.0 9.004-150.0 GRID 7 -.707107-.7071070.0 GRID 8 8.698-15-1.0 0.0 GRID 9 .7071068-.7071070.0 GRID 10 .7071068.70710681.0 GRID 11 2.06-15 1.0 1.0 GRID 12 -.707107.70710681.0 GRID 13 -1.0 9.004-151.0 GRID 14 -.707107-.7071071.0 GRID 15 8.698-15-1.0 1.0 GRID 16 .7071068-.7071071.0 GRID 17 .3254219-6.154-20.0 GRID 18 9.8468-2.35124360.0 GRID 19 -0.14533-.2592060.0 GRID 20 -.0442730.2844711.0 GRID 21 .3224226-.2460451.0 GRID 22 -.169874-.2417461.0 GRID 23 -5.965-2-.291461.5227236 GRID 24 -.412743.1771685.4583333 GRID 25 -.271964-.345838.4791667 GRID 26 .1950392-.464081.4583333 GRID 27 .2936736-.1216440.5 GRID 28 .4547628.1859033.5416667 GRID 29 -4.085-20.440721.4791667 GRID 30 -.247058.3278403.4868056 GRID 31 .2479088.3405819.5163716 GRID 32 .2528394-.303703.4738152 GRID 33 -0.35812-7.943-2.4813956 $$ $$ CBAR Elements $$ CBAR 37 3 11.0 0.0 0.0 CBAR 38 4 31.0 0.0 0.0 CBAR 39 5 41.0 0.0 0.0 CBAR 40 6 51.0 0.0 0.0 CBAR 41 7 61.0 0.0 0.0 CBAR 42 8 71.0 0.0 0.0 CBAR 43 9 81.0 0.0 0.0 CBAR 44 1 91.0 0.0 0.0 CBAR 45 2 101.0 0.0 0.0 CBAR 46 10 111.0 0.0 0.0 CBAR 47 11 121.0 0.0 0.0 CBAR 48 12 131.0 0.0 0.0 CBAR 49 13 141.0 0.0 0.0 CBAR 50 14 151.0 0.0 0.0 CBAR 51 15 161.0 0.0 0.0 CBAR 52 16 21.0 0.0 0.0 CBAR 53 1 21.0 0.0 0.0 $ $HMMOVE 1 $ 37THRU 53 $$ $$ CTRIA3 Data $$ CTRIA3 117 0 1 9 17 CTRIA3 118 0 17 19 18 CTRIA3 119 0 16 2 21 CTRIA3 120 0 22 21 20 $ $HMMOVE 1 $ 117THRU 120 $$ $$ CQUAD4 Elements $$ CQUAD4 19 0 3 1 17 18 CQUAD4 20 0 4 3 18 5 CQUAD4 21 0 6 5 18 19 CQUAD4 22 0 7 6 19 8 CQUAD4 23 0 9 8 19 17 CQUAD4 24 0 2 10 20 21 CQUAD4 25 0 10 11 12 20 CQUAD4 26 0 12 13 22 20 CQUAD4 27 0 13 14 15 22 CQUAD4 28 0 15 16 21 22 CQUAD4 29 0 11 10 3 4 CQUAD4 30 0 13 12 5 6 CQUAD4 31 0 14 13 6 7 CQUAD4 32 0 16 15 8 9 CQUAD4 33 0 2 16 9 1 CQUAD4 34 0 1 3 10 2 CQUAD4 35 0 5 12 11 4 CQUAD4 36 0 8 15 14 7 $ $HMMOVE 1 $ 19THRU 36 $$ $$ CPYRA Elements 5-noded $$ CPYRA 1 0 11 4 3 10 29 CPYRA 2 0 13 6 5 12 24 CPYRA 3 0 14 7 6 13 25 CPYRA 4 0 16 9 8 15 26 CPYRA 5 0 2 1 9 16 27 CPYRA 6 0 1 2 10 3 28 CPYRA 7 0 5 4 11 12 29 CPYRA 8 0 8 7 14 15 25 CPYRA 9 0 2 21 20 10 28 CPYRA 10 0 10 20 12 11 29 CPYRA 11 0 12 20 22 13 24 CPYRA 12 0 13 22 15 14 25 CPYRA 13 0 15 22 21 16 26 CPYRA 14 0 3 18 17 1 28 CPYRA 15 0 4 5 18 3 29 CPYRA 16 0 6 19 18 5 24 CPYRA 17 0 7 8 19 6 25 CPYRA 18 0 9 17 19 8 26 $ $HMMOVE 1 $ 1THRU 18 $$ $$ CTETRA elements 4-noded $$ CTETRA 54 0 29 30 27 20 CTETRA 55 0 23 8 25 19 CTETRA 56 0 15 25 22 23 CTETRA 57 0 5 18 29 30 CTETRA 58 0 23 27 33 22 CTETRA 59 0 16 2 27 21 CTETRA 60 0 32 19 17 26 CTETRA 61 0 17 19 27 18 CTETRA 62 0 31 10 29 20 CTETRA 63 0 27 2 28 21 CTETRA 64 0 17 1 28 27 CTETRA 65 0 27 20 22 21 CTETRA 66 0 32 26 17 9 CTETRA 67 0 31 20 29 27 CTETRA 68 0 28 20 27 21 CTETRA 69 0 27 24 22 20 CTETRA 70 0 28 2 27 1 CTETRA 71 0 6 13 33 24 CTETRA 72 0 19 24 33 27 CTETRA 73 0 29 20 12 30 CTETRA 74 0 16 21 32 26 CTETRA 75 0 23 22 33 25 CTETRA 76 0 31 18 29 3 CTETRA 77 0 29 18 31 27 CTETRA 78 0 23 25 33 19 CTETRA 79 0 21 26 23 32 CTETRA 80 0 29 18 27 30 CTETRA 81 0 29 30 12 5 CTETRA 82 0 27 19 32 23 CTETRA 83 0 28 18 17 27 CTETRA 84 0 24 33 22 13 CTETRA 85 0 29 10 31 3 CTETRA 86 0 23 8 15 25 CTETRA 87 0 27 18 19 24 CTETRA 88 0 17 1 27 9 CTETRA 89 0 16 26 32 9 CTETRA 90 0 26 8 23 19 CTETRA 91 0 15 23 22 26 CTETRA 92 0 21 32 23 27 CTETRA 93 0 32 19 26 23 CTETRA 94 0 26 8 15 23 CTETRA 95 0 30 24 27 20 CTETRA 96 0 5 18 30 24 CTETRA 97 0 30 20 12 24 CTETRA 98 0 30 18 27 24 CTETRA 99 0 30 24 12 5 CTETRA 100 0 21 27 23 22 CTETRA 101 0 22 33 25 13 CTETRA 102 0 28 10 31 20 CTETRA 103 0 28 20 31 27 CTETRA 104 0 28 18 31 3 CTETRA 105 0 31 18 28 27 CTETRA 106 0 31 10 28 3 CTETRA 107 0 6 13 25 33 CTETRA 108 0 16 32 27 9 CTETRA 109 0 21 22 23 26 CTETRA 110 0 27 19 17 32 CTETRA 111 0 27 32 17 9 CTETRA 112 0 16 21 27 32 CTETRA 113 0 19 25 33 6 CTETRA 114 0 24 27 22 33 CTETRA 115 0 23 19 33 27 CTETRA 116 0 19 6 33 24 $ $HMMOVE 1 $ 54THRU 116 $$ $$------------------------------------------------------------------------------$ $$ HyperMesh name and color information for generic components $ $$------------------------------------------------------------------------------$ $HMNAME COMP 1"misc1" $HWCOLOR COMP 1 11 $ $ $ $$ $$------------------------------------------------------------------------------$ $$ HyperMesh Commands for loadcollectors name and color information $ $$------------------------------------------------------------------------------$ ENDDATA $$ $$------------------------------------------------------------------------------$$ $$ Data Definition for AutoDV $$ $$------------------------------------------------------------------------------$$ $$ $$-----------------------------------------------------------------------------$$ $$ Design Variables Card for Control Perturbations $$ $$-----------------------------------------------------------------------------$$ $$ $$------------------------------------------------------------------------------$ $$ Domain Element Definitions $ $$------------------------------------------------------------------------------$ $$ $$------------------------------------------------------------------------------$$ $$ Control Perturbation $$ $$------------------------------------------------------------------------------$$ tests/meshes/nastran/cylinder_cells_first.fem000066400000000000000000000262671456244072500220730ustar00rootroot00000000000000$$ $$ Optistruct Input Deck Generated by HyperMesh Version : 2017.3.0.17 $$ Generated using HyperMesh-Optistruct Template Version : 2017.3 $$ $$ Template: optistruct $$ $$ $$ optistruct $ $$------------------------------------------------------------------------------$ $$ Case Control Cards $ $$------------------------------------------------------------------------------$ $$-------------------------------------------------------------- $$ HYPERMESH TAGS $$-------------------------------------------------------------- $$BEGIN TAGS $$END TAGS $ BEGIN BULK $$ $$ Stacking Information for Ply-Based Composite Definition $$ $$ $$ CBAR Elements $$ CBAR 37 3 11.0 0.0 0.0 CBAR 38 4 31.0 0.0 0.0 CBAR 39 5 41.0 0.0 0.0 CBAR 40 6 51.0 0.0 0.0 CBAR 41 7 61.0 0.0 0.0 CBAR 42 8 71.0 0.0 0.0 CBAR 43 9 81.0 0.0 0.0 CBAR 44 1 91.0 0.0 0.0 CBAR 45 2 101.0 0.0 0.0 CBAR 46 10 111.0 0.0 0.0 CBAR 47 11 121.0 0.0 0.0 CBAR 48 12 131.0 0.0 0.0 CBAR 49 13 141.0 0.0 0.0 CBAR 50 14 151.0 0.0 0.0 CBAR 51 15 161.0 0.0 0.0 CBAR 52 16 21.0 0.0 0.0 CBAR 53 1 21.0 0.0 0.0 $ $HMMOVE 1 $ 37THRU 53 $$ $$ CTRIA3 Data $$ CTRIA3 117 0 1 9 17 CTRIA3 118 0 17 19 18 CTRIA3 119 0 16 2 21 CTRIA3 120 0 22 21 20 $ $HMMOVE 1 $ 117THRU 120 $$ $$ CQUAD4 Elements $$ CQUAD4 19 0 3 1 17 18 CQUAD4 20 0 4 3 18 5 CQUAD4 21 0 6 5 18 19 CQUAD4 22 0 7 6 19 8 CQUAD4 23 0 9 8 19 17 CQUAD4 24 0 2 10 20 21 CQUAD4 25 0 10 11 12 20 CQUAD4 26 0 12 13 22 20 CQUAD4 27 0 13 14 15 22 CQUAD4 28 0 15 16 21 22 CQUAD4 29 0 11 10 3 4 CQUAD4 30 0 13 12 5 6 CQUAD4 31 0 14 13 6 7 CQUAD4 32 0 16 15 8 9 CQUAD4 33 0 2 16 9 1 CQUAD4 34 0 1 3 10 2 CQUAD4 35 0 5 12 11 4 CQUAD4 36 0 8 15 14 7 $ $HMMOVE 1 $ 19THRU 36 $$ $$ CPYRA Elements 5-noded $$ CPYRA 1 0 11 4 3 10 29 CPYRA 2 0 13 6 5 12 24 CPYRA 3 0 14 7 6 13 25 CPYRA 4 0 16 9 8 15 26 CPYRA 5 0 2 1 9 16 27 CPYRA 6 0 1 2 10 3 28 CPYRA 7 0 5 4 11 12 29 CPYRA 8 0 8 7 14 15 25 CPYRA 9 0 2 21 20 10 28 CPYRA 10 0 10 20 12 11 29 CPYRA 11 0 12 20 22 13 24 CPYRA 12 0 13 22 15 14 25 CPYRA 13 0 15 22 21 16 26 CPYRA 14 0 3 18 17 1 28 CPYRA 15 0 4 5 18 3 29 CPYRA 16 0 6 19 18 5 24 CPYRA 17 0 7 8 19 6 25 CPYRA 18 0 9 17 19 8 26 $ $HMMOVE 1 $ 1THRU 18 $$ $$ CTETRA elements 4-noded $$ CTETRA 54 0 29 30 27 20 CTETRA 55 0 23 8 25 19 CTETRA 56 0 15 25 22 23 CTETRA 57 0 5 18 29 30 CTETRA 58 0 23 27 33 22 CTETRA 59 0 16 2 27 21 CTETRA 60 0 32 19 17 26 CTETRA 61 0 17 19 27 18 CTETRA 62 0 31 10 29 20 CTETRA 63 0 27 2 28 21 CTETRA 64 0 17 1 28 27 CTETRA 65 0 27 20 22 21 CTETRA 66 0 32 26 17 9 CTETRA 67 0 31 20 29 27 CTETRA 68 0 28 20 27 21 CTETRA 69 0 27 24 22 20 CTETRA 70 0 28 2 27 1 CTETRA 71 0 6 13 33 24 CTETRA 72 0 19 24 33 27 CTETRA 73 0 29 20 12 30 CTETRA 74 0 16 21 32 26 CTETRA 75 0 23 22 33 25 CTETRA 76 0 31 18 29 3 CTETRA 77 0 29 18 31 27 CTETRA 78 0 23 25 33 19 CTETRA 79 0 21 26 23 32 CTETRA 80 0 29 18 27 30 CTETRA 81 0 29 30 12 5 CTETRA 82 0 27 19 32 23 CTETRA 83 0 28 18 17 27 CTETRA 84 0 24 33 22 13 CTETRA 85 0 29 10 31 3 CTETRA 86 0 23 8 15 25 CTETRA 87 0 27 18 19 24 CTETRA 88 0 17 1 27 9 CTETRA 89 0 16 26 32 9 CTETRA 90 0 26 8 23 19 CTETRA 91 0 15 23 22 26 CTETRA 92 0 21 32 23 27 CTETRA 93 0 32 19 26 23 CTETRA 94 0 26 8 15 23 CTETRA 95 0 30 24 27 20 CTETRA 96 0 5 18 30 24 CTETRA 97 0 30 20 12 24 CTETRA 98 0 30 18 27 24 CTETRA 99 0 30 24 12 5 CTETRA 100 0 21 27 23 22 CTETRA 101 0 22 33 25 13 CTETRA 102 0 28 10 31 20 CTETRA 103 0 28 20 31 27 CTETRA 104 0 28 18 31 3 CTETRA 105 0 31 18 28 27 CTETRA 106 0 31 10 28 3 CTETRA 107 0 6 13 25 33 CTETRA 108 0 16 32 27 9 CTETRA 109 0 21 22 23 26 CTETRA 110 0 27 19 17 32 CTETRA 111 0 27 32 17 9 CTETRA 112 0 16 21 27 32 CTETRA 113 0 19 25 33 6 CTETRA 114 0 24 27 22 33 CTETRA 115 0 23 19 33 27 CTETRA 116 0 19 6 33 24 $ $HMMOVE 1 $ 54THRU 116 $$ $$ GRID Data $$ GRID 1 1.0 -2.45-160.0 GRID 2 1.0 -2.45-161.0 GRID 3 .7071068.70710680.0 GRID 4 2.06-15 1.0 0.0 GRID 5 -.707107.70710680.0 GRID 6 -1.0 9.004-150.0 GRID 7 -.707107-.7071070.0 GRID 8 8.698-15-1.0 0.0 GRID 9 .7071068-.7071070.0 GRID 10 .7071068.70710681.0 GRID 11 2.06-15 1.0 1.0 GRID 12 -.707107.70710681.0 GRID 13 -1.0 9.004-151.0 GRID 14 -.707107-.7071071.0 GRID 15 8.698-15-1.0 1.0 GRID 16 .7071068-.7071071.0 GRID 17 .3254219-6.154-20.0 GRID 18 9.8468-2.35124360.0 GRID 19 -0.14533-.2592060.0 GRID 20 -.0442730.2844711.0 GRID 21 .3224226-.2460451.0 GRID 22 -.169874-.2417461.0 GRID 23 -5.965-2-.291461.5227236 GRID 24 -.412743.1771685.4583333 GRID 25 -.271964-.345838.4791667 GRID 26 .1950392-.464081.4583333 GRID 27 .2936736-.1216440.5 GRID 28 .4547628.1859033.5416667 GRID 29 -4.085-20.440721.4791667 GRID 30 -.247058.3278403.4868056 GRID 31 .2479088.3405819.5163716 GRID 32 .2528394-.303703.4738152 GRID 33 -0.35812-7.943-2.4813956 $ $$------------------------------------------------------------------------------$ $$ HyperMesh name and color information for generic components $ $$------------------------------------------------------------------------------$ $HMNAME COMP 1"misc1" $HWCOLOR COMP 1 11 $ $ $ $$ $$------------------------------------------------------------------------------$ $$ HyperMesh Commands for loadcollectors name and color information $ $$------------------------------------------------------------------------------$ ENDDATA $$ $$------------------------------------------------------------------------------$$ $$ Data Definition for AutoDV $$ $$------------------------------------------------------------------------------$$ $$ $$-----------------------------------------------------------------------------$$ $$ Design Variables Card for Control Perturbations $$ $$-----------------------------------------------------------------------------$$ $$ $$------------------------------------------------------------------------------$ $$ Domain Element Definitions $ $$------------------------------------------------------------------------------$ $$ $$------------------------------------------------------------------------------$$ $$ Control Perturbation $$ $$------------------------------------------------------------------------------$$ tests/meshes/netgen/000077500000000000000000000000001456244072500147755ustar00rootroot00000000000000tests/meshes/netgen/periodic_1d.vol000066400000000000000000000231761456244072500177120ustar00rootroot00000000000000# Generated by NETGEN v6.2.2103-39-g3165e042 mesh3d dimension 1 geomtype 0 # surfnr bcnr domin domout np p1 p2 p3 surfaceelements 0 # matnr np p1 p2 p3 p4 volumeelements 0 # surfid 0 p1 p2 trignum1 trignum2 domin/surfnr1 domout/surfnr2 ednr1 dist1 ednr2 dist2 edgesegmentsgi2 50 1 0 1 2 -1 -1 -1 -1 1 0 1 0 1 0 2 3 -1 -1 -1 -1 1 0 1 0 1 0 3 4 -1 -1 -1 -1 1 0 1 0 1 0 4 5 -1 -1 -1 -1 1 0 1 0 1 0 5 6 -1 -1 -1 -1 1 0 1 0 1 0 6 7 -1 -1 -1 -1 1 0 1 0 1 0 7 8 -1 -1 -1 -1 1 0 1 0 1 0 8 9 -1 -1 -1 -1 1 0 1 0 1 0 9 10 -1 -1 -1 -1 1 0 1 0 1 0 10 11 -1 -1 -1 -1 1 0 1 0 1 0 11 12 -1 -1 -1 -1 1 0 1 0 1 0 12 13 -1 -1 -1 -1 1 0 1 0 1 0 13 14 -1 -1 -1 -1 1 0 1 0 1 0 14 15 -1 -1 -1 -1 1 0 1 0 1 0 15 16 -1 -1 -1 -1 1 0 1 0 1 0 16 17 -1 -1 -1 -1 1 0 1 0 1 0 17 18 -1 -1 -1 -1 1 0 1 0 1 0 18 19 -1 -1 -1 -1 1 0 1 0 1 0 19 20 -1 -1 -1 -1 1 0 1 0 1 0 20 21 -1 -1 -1 -1 1 0 1 0 1 0 21 22 -1 -1 -1 -1 1 0 1 0 1 0 22 23 -1 -1 -1 -1 1 0 1 0 1 0 23 24 -1 -1 -1 -1 1 0 1 0 1 0 24 25 -1 -1 -1 -1 1 0 1 0 1 0 25 26 -1 -1 -1 -1 1 0 1 0 1 0 26 27 -1 -1 -1 -1 1 0 1 0 1 0 27 28 -1 -1 -1 -1 1 0 1 0 1 0 28 29 -1 -1 -1 -1 1 0 1 0 1 0 29 30 -1 -1 -1 -1 1 0 1 0 1 0 30 31 -1 -1 -1 -1 1 0 1 0 1 0 31 32 -1 -1 -1 -1 1 0 1 0 1 0 32 33 -1 -1 -1 -1 1 0 1 0 1 0 33 34 -1 -1 -1 -1 1 0 1 0 1 0 34 35 -1 -1 -1 -1 1 0 1 0 1 0 35 36 -1 -1 -1 -1 1 0 1 0 1 0 36 37 -1 -1 -1 -1 1 0 1 0 1 0 37 38 -1 -1 -1 -1 1 0 1 0 1 0 38 39 -1 -1 -1 -1 1 0 1 0 1 0 39 40 -1 -1 -1 -1 1 0 1 0 1 0 40 41 -1 -1 -1 -1 1 0 1 0 1 0 41 42 -1 -1 -1 -1 1 0 1 0 1 0 42 43 -1 -1 -1 -1 1 0 1 0 1 0 43 44 -1 -1 -1 -1 1 0 1 0 1 0 44 45 -1 -1 -1 -1 1 0 1 0 1 0 45 46 -1 -1 -1 -1 1 0 1 0 1 0 46 47 -1 -1 -1 -1 1 0 1 0 1 0 47 48 -1 -1 -1 -1 1 0 1 0 1 0 48 49 -1 -1 -1 -1 1 0 1 0 1 0 49 50 -1 -1 -1 -1 1 0 1 0 1 0 50 51 -1 -1 -1 -1 1 0 1 0 # X Y Z points 51 0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0200000000000000 0.0000000000000000 0.0000000000000000 0.0400000000000000 0.0000000000000000 0.0000000000000000 0.0600000000000000 0.0000000000000000 0.0000000000000000 0.0800000000000000 0.0000000000000000 0.0000000000000000 0.1000000000000000 0.0000000000000000 0.0000000000000000 0.1200000000000000 0.0000000000000000 0.0000000000000000 0.1400000000000000 0.0000000000000000 0.0000000000000000 0.1600000000000000 0.0000000000000000 0.0000000000000000 0.1800000000000000 0.0000000000000000 0.0000000000000000 0.2000000000000000 0.0000000000000000 0.0000000000000000 0.2200000000000000 0.0000000000000000 0.0000000000000000 0.2400000000000000 0.0000000000000000 0.0000000000000000 0.2600000000000000 0.0000000000000000 0.0000000000000000 0.2800000000000000 0.0000000000000000 0.0000000000000000 0.3000000000000000 0.0000000000000000 0.0000000000000000 0.3200000000000000 0.0000000000000000 0.0000000000000000 0.3400000000000000 0.0000000000000000 0.0000000000000000 0.3600000000000000 0.0000000000000000 0.0000000000000000 0.3800000000000000 0.0000000000000000 0.0000000000000000 0.4000000000000000 0.0000000000000000 0.0000000000000000 0.4200000000000000 0.0000000000000000 0.0000000000000000 0.4400000000000000 0.0000000000000000 0.0000000000000000 0.4600000000000000 0.0000000000000000 0.0000000000000000 0.4800000000000000 0.0000000000000000 0.0000000000000000 0.5000000000000000 0.0000000000000000 0.0000000000000000 0.5200000000000000 0.0000000000000000 0.0000000000000000 0.5400000000000000 0.0000000000000000 0.0000000000000000 0.5600000000000001 0.0000000000000000 0.0000000000000000 0.5800000000000000 0.0000000000000000 0.0000000000000000 0.6000000000000000 0.0000000000000000 0.0000000000000000 0.6200000000000000 0.0000000000000000 0.0000000000000000 0.6400000000000000 0.0000000000000000 0.0000000000000000 0.6600000000000000 0.0000000000000000 0.0000000000000000 0.6800000000000000 0.0000000000000000 0.0000000000000000 0.7000000000000000 0.0000000000000000 0.0000000000000000 0.7200000000000000 0.0000000000000000 0.0000000000000000 0.7400000000000000 0.0000000000000000 0.0000000000000000 0.7600000000000000 0.0000000000000000 0.0000000000000000 0.7800000000000000 0.0000000000000000 0.0000000000000000 0.8000000000000000 0.0000000000000000 0.0000000000000000 0.8200000000000000 0.0000000000000000 0.0000000000000000 0.8400000000000000 0.0000000000000000 0.0000000000000000 0.8600000000000000 0.0000000000000000 0.0000000000000000 0.8800000000000000 0.0000000000000000 0.0000000000000000 0.9000000000000000 0.0000000000000000 0.0000000000000000 0.9200000000000000 0.0000000000000000 0.0000000000000000 0.9399999999999999 0.0000000000000000 0.0000000000000000 0.9600000000000000 0.0000000000000000 0.0000000000000000 0.9800000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000 # pnum index pointelements 2 1 1 51 2 identifications 1 1 51 1 identificationtypes 1 2 endmesh tests/meshes/netgen/periodic_2d.vol000066400000000000000000000160061456244072500177050ustar00rootroot00000000000000# Generated by NETGEN v6.2.2103-39-g3165e042 mesh3d dimension 2 geomtype 0 # surfnr bcnr domin domout np p1 p2 p3 surfaceelements 58 2 1 0 0 3 1 5 17 2 1 0 0 3 5 6 21 2 1 0 0 3 6 7 22 2 1 0 0 3 6 22 21 2 1 0 0 3 7 8 23 2 1 0 0 3 7 23 22 2 1 0 0 3 2 24 8 2 1 0 0 3 8 24 23 2 1 0 0 3 2 9 24 2 1 0 0 3 9 10 25 2 1 0 0 3 9 25 24 2 1 0 0 3 10 11 26 2 1 0 0 3 10 26 25 2 1 0 0 3 11 12 27 2 1 0 0 3 11 27 26 2 1 0 0 3 3 13 12 2 1 0 0 3 13 14 28 2 1 0 0 3 14 15 29 2 1 0 0 3 14 29 28 2 1 0 0 3 15 16 30 2 1 0 0 3 15 30 29 2 1 0 0 3 4 31 16 2 1 0 0 3 16 31 30 2 1 0 0 3 4 20 31 2 1 0 0 3 17 32 18 2 1 0 0 3 18 33 19 2 1 0 0 3 18 32 33 2 1 0 0 3 19 34 20 2 1 0 0 3 20 34 31 2 1 0 0 3 19 33 34 2 1 0 0 3 12 13 27 2 1 0 0 3 13 28 27 2 1 0 0 3 5 21 17 2 1 0 0 3 22 23 35 2 1 0 0 3 21 22 36 2 1 0 0 3 22 35 36 2 1 0 0 3 26 27 37 2 1 0 0 3 27 28 37 2 1 0 0 3 23 24 25 2 1 0 0 3 23 25 35 2 1 0 0 3 30 31 38 2 1 0 0 3 31 34 38 2 1 0 0 3 29 30 38 2 1 0 0 3 28 29 39 2 1 0 0 3 28 39 37 2 1 0 0 3 29 38 39 2 1 0 0 3 17 21 32 2 1 0 0 3 21 36 32 2 1 0 0 3 25 26 40 2 1 0 0 3 32 36 33 2 1 0 0 3 26 37 40 2 1 0 0 3 33 38 34 2 1 0 0 3 33 36 38 2 1 0 0 3 25 40 35 2 1 0 0 3 36 39 38 2 1 0 0 3 35 39 36 2 1 0 0 3 35 40 39 2 1 0 0 3 37 39 40 # matnr np p1 p2 p3 p4 volumeelements 0 # surfid 0 p1 p2 trignum1 trignum2 domin/surfnr1 domout/surfnr2 ednr1 dist1 ednr2 dist2 edgesegmentsgi2 20 1 0 1 5 -1 -1 1 0 1 0 1 0.2 1 0 5 6 -1 -1 1 0 1 0.2 1 0.4 1 0 6 7 -1 -1 1 0 1 0.4 1 0.6 1 0 7 8 -1 -1 1 0 1 0.6 1 0.8 1 0 8 2 -1 -1 1 0 1 0.8 1 1 2 0 2 9 -1 -1 1 0 2 0 2 0.2 2 0 9 10 -1 -1 1 0 2 0.2 2 0.4 2 0 10 11 -1 -1 1 0 2 0.4 2 0.6 2 0 11 12 -1 -1 1 0 2 0.6 2 0.8 2 0 12 3 -1 -1 1 0 2 0.8 2 1 3 0 3 13 -1 -1 1 0 3 0 3 0.2 3 0 13 14 -1 -1 1 0 3 0.2 3 0.4 3 0 14 15 -1 -1 1 0 3 0.4 3 0.6 3 0 15 16 -1 -1 1 0 3 0.6 3 0.8 3 0 16 4 -1 -1 1 0 3 0.8 3 1 4 0 1 17 -1 -1 0 1 4 0 4 0.2 4 0 17 18 -1 -1 0 1 4 0.2 4 0.4 4 0 18 19 -1 -1 0 1 4 0.4 4 0.6 4 0 19 20 -1 -1 0 1 4 0.6 4 0.8 4 0 20 4 -1 -1 0 1 4 0.8 4 1 # X Y Z points 40 0.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000 0.2000000000000000 0.0000000000000000 0.0000000000000000 0.4000000000000000 0.0000000000000000 0.0000000000000000 0.6000000000000000 0.0000000000000000 0.0000000000000000 0.8000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000 0.2000000000000000 0.0000000000000000 1.0000000000000000 0.4000000000000000 0.0000000000000000 1.0000000000000000 0.6000000000000000 0.0000000000000000 1.0000000000000000 0.8000000000000000 0.0000000000000000 0.7999999999999999 1.0000000000000000 0.0000000000000000 0.6000000000000000 1.0000000000000000 0.0000000000000000 0.4000000000000000 1.0000000000000000 0.0000000000000000 0.2000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000 0.2000000000000000 0.0000000000000000 0.0000000000000000 0.4000000000000000 0.0000000000000000 0.0000000000000000 0.6000000000000000 0.0000000000000000 0.0000000000000000 0.8000000000000000 0.0000000000000000 0.2737029466317127 0.1811747818216966 0.0000000000000000 0.4805348579459315 0.1852935472807671 0.0000000000000000 0.6827590117435046 0.1702890061939871 0.0000000000000000 0.8575695844442716 0.1419063764469471 0.0000000000000000 0.8111112850985802 0.3258703253208415 0.0000000000000000 0.8493339534816288 0.5262364626047286 0.0000000000000000 0.8421283897191041 0.7318614438631723 0.0000000000000000 0.6601606467397222 0.8032633168034399 0.0000000000000000 0.4765343016929663 0.8179836454001187 0.0000000000000000 0.3132853271934791 0.8629930180472398 0.0000000000000000 0.1584925502078927 0.8390807603910830 0.0000000000000000 0.1662260298847409 0.3347019222223993 0.0000000000000000 0.1698338083646673 0.5130730339035593 0.0000000000000000 0.1324637082656786 0.6819019947250892 0.0000000000000000 0.5818135591952022 0.3542155081169817 0.0000000000000000 0.3642445694293263 0.4057099958862074 0.0000000000000000 0.7111939984221883 0.6337182845699614 0.0000000000000000 0.3154224090519101 0.6697496604451058 0.0000000000000000 0.5278793480475702 0.5943130585988371 0.0000000000000000 0.6923017137632204 0.4803955670550934 0.0000000000000000 # pnum index pointelements 4 1 1 2 2 3 3 4 4 identifications 6 2 1 4 3 4 4 9 17 4 10 18 4 11 19 4 12 20 4 identificationtypes 4 1 1 1 2 bcnames 4 1 outer 2 periodic 3 outer 4 periodic cd2names 4 1 2 3 4 # Surfnr Red Green Blue face_colours 1 2 0.00000000 1.00000000 0.00000000 endmesh tests/meshes/netgen/periodic_3d.vol000066400000000000000000000457511456244072500177170ustar00rootroot00000000000000# Generated by NETGEN v6.2.2103-39-g3165e042 mesh3d dimension 3 geomtype 0 # surfnr bcnr domin domout np p1 p2 p3 surfaceelements 108 1 1 1 0 3 1 9 32 1 1 1 0 3 9 10 33 1 1 1 0 3 4 34 10 1 1 1 0 3 10 34 33 1 1 1 0 3 4 28 34 1 1 1 0 3 3 31 11 1 1 1 0 3 11 35 12 1 1 1 0 3 7 12 36 1 1 1 0 3 7 36 27 1 1 1 0 3 12 35 36 1 1 1 0 3 27 37 28 1 1 1 0 3 28 37 34 1 1 1 0 3 27 36 37 3 6 1 0 3 49 51 53 1 1 1 0 3 9 33 32 3 6 1 0 3 30 51 49 1 1 1 0 3 35 37 36 1 1 1 0 3 33 34 37 1 1 1 0 3 31 32 33 1 1 1 0 3 11 31 35 1 1 1 0 3 31 33 35 1 1 1 0 3 33 37 35 7 2 1 0 3 1 22 9 7 2 1 0 3 9 38 10 7 2 1 0 3 4 10 16 3 6 1 0 3 49 53 50 7 2 1 0 3 10 38 16 7 2 1 0 3 6 15 26 7 2 1 0 3 15 16 39 7 2 1 0 3 15 39 26 3 6 1 0 3 51 52 53 7 2 1 0 3 2 25 21 7 2 1 0 3 21 40 22 7 2 1 0 3 25 26 39 7 2 1 0 3 9 22 40 7 2 1 0 3 21 25 40 7 2 1 0 3 25 39 40 7 2 1 0 3 9 40 38 7 2 1 0 3 16 38 39 7 2 1 0 3 38 40 39 4 4 1 0 3 8 13 17 4 4 1 0 3 13 14 41 4 4 1 0 3 7 42 14 4 4 1 0 3 14 42 41 4 4 1 0 3 7 27 42 3 6 1 0 3 29 30 49 4 4 1 0 3 15 43 16 4 4 1 0 3 4 16 44 4 4 1 0 3 4 44 28 4 4 1 0 3 16 43 44 3 6 1 0 3 19 29 49 4 4 1 0 3 6 18 15 4 4 1 0 3 27 28 45 4 4 1 0 3 27 45 42 4 4 1 0 3 28 44 45 4 4 1 0 3 13 41 17 4 4 1 0 3 43 45 44 4 4 1 0 3 41 42 45 4 4 1 0 3 15 18 43 4 4 1 0 3 17 41 18 4 4 1 0 3 18 41 43 4 4 1 0 3 41 45 43 2 5 1 0 3 8 17 24 2 5 1 0 3 17 18 46 2 5 1 0 3 6 26 18 2 5 1 0 3 18 26 46 3 6 1 0 3 31 50 53 2 5 1 0 3 5 23 47 2 5 1 0 3 23 24 47 2 5 1 0 3 2 30 25 2 5 1 0 3 25 48 26 2 5 1 0 3 25 30 48 2 5 1 0 3 5 47 29 2 5 1 0 3 29 48 30 2 5 1 0 3 17 46 24 2 5 1 0 3 29 47 48 2 5 1 0 3 24 46 47 2 5 1 0 3 46 48 47 3 6 1 0 3 32 53 52 2 5 1 0 3 26 48 46 3 6 1 0 3 5 29 19 3 6 1 0 3 19 49 20 3 6 1 0 3 3 20 50 3 6 1 0 3 3 50 31 3 6 1 0 3 20 49 50 3 6 1 0 3 2 21 30 3 6 1 0 3 21 22 51 3 6 1 0 3 1 52 22 3 6 1 0 3 22 52 51 3 6 1 0 3 1 32 52 3 6 1 0 3 21 51 30 3 6 1 0 3 31 53 32 8 3 1 0 3 3 11 20 8 3 1 0 3 11 12 54 8 3 1 0 3 7 14 12 8 3 1 0 3 12 14 54 8 3 1 0 3 8 24 13 8 3 1 0 3 13 55 14 8 3 1 0 3 13 24 55 8 3 1 0 3 5 19 23 8 3 1 0 3 19 20 56 8 3 1 0 3 23 55 24 8 3 1 0 3 11 56 20 8 3 1 0 3 19 56 23 8 3 1 0 3 23 56 55 8 3 1 0 3 11 54 56 8 3 1 0 3 14 55 54 8 3 1 0 3 54 55 56 # matnr np p1 p2 p3 p4 volumeelements 166 1 4 33 57 59 61 1 4 12 14 54 36 1 4 33 38 59 57 1 4 21 40 51 60 1 4 49 51 53 57 1 4 11 35 54 58 1 4 57 59 61 64 1 4 11 20 58 56 1 4 54 55 56 61 1 4 15 39 62 43 1 4 39 43 59 62 1 4 55 56 61 64 1 4 1 9 65 22 1 4 49 57 63 60 1 4 41 45 59 61 1 4 29 47 60 63 1 4 29 47 48 60 1 4 46 47 60 48 1 4 9 38 65 40 1 4 24 46 47 64 1 4 39 40 62 59 1 4 21 30 60 51 1 4 1 9 32 65 1 4 57 59 64 62 1 4 56 58 61 64 1 4 38 39 59 40 1 4 20 49 58 56 1 4 36 37 42 61 1 4 35 36 61 37 1 4 27 36 37 42 1 4 35 36 54 61 1 4 37 42 61 45 1 4 5 19 23 63 1 4 14 41 55 61 1 4 23 47 63 64 1 4 9 22 40 65 1 4 31 32 33 53 1 4 25 26 62 48 1 4 23 24 47 64 1 4 40 57 62 59 1 4 56 58 64 63 1 4 22 51 65 52 1 4 29 49 63 60 1 4 34 37 59 45 1 4 33 53 57 58 1 4 23 24 64 55 1 4 32 33 53 65 1 4 11 12 54 35 1 4 43 44 59 45 1 4 21 25 60 30 1 4 40 51 57 65 1 4 13 14 41 55 1 4 22 40 65 51 1 4 41 46 64 62 1 4 3 11 20 58 1 4 41 43 59 45 1 4 10 33 38 34 1 4 31 33 35 58 1 4 21 25 40 60 1 4 2 21 30 25 1 4 24 41 46 64 1 4 17 18 46 41 1 4 49 57 58 63 1 4 4 10 16 44 1 4 10 34 38 44 1 4 17 24 41 46 1 4 19 29 49 63 1 4 33 37 61 59 1 4 33 38 57 65 1 4 11 31 35 58 1 4 38 40 59 57 1 4 7 12 36 14 1 4 30 49 60 51 1 4 27 37 45 42 1 4 14 36 42 61 1 4 15 18 43 62 1 4 19 20 56 49 1 4 41 55 61 64 1 4 21 22 51 40 1 4 10 16 44 38 1 4 57 58 63 64 1 4 15 16 39 43 1 4 25 30 48 60 1 4 46 48 60 62 1 4 12 35 36 54 1 4 33 35 61 37 1 4 26 46 62 48 1 4 33 35 58 61 1 4 25 48 62 60 1 4 3 20 50 58 1 4 18 41 62 46 1 4 25 40 60 62 1 4 37 45 61 59 1 4 40 57 60 62 1 4 23 55 64 56 1 4 38 40 57 65 1 4 41 59 62 64 1 4 49 50 58 53 1 4 14 36 61 54 1 4 51 52 53 65 1 4 25 26 39 62 1 4 34 38 44 59 1 4 9 32 65 33 1 4 51 53 57 65 1 4 16 38 59 44 1 4 23 56 64 63 1 4 14 54 61 55 1 4 6 15 26 18 1 4 15 18 62 26 1 4 54 56 58 61 1 4 3 31 58 50 1 4 49 56 63 58 1 4 5 19 63 29 1 4 1 32 52 65 1 4 4 28 34 44 1 4 35 54 58 61 1 4 4 10 44 34 1 4 49 53 58 57 1 4 1 22 65 52 1 4 41 59 64 61 1 4 29 30 49 60 1 4 5 29 63 47 1 4 9 10 33 38 1 4 40 51 60 57 1 4 18 41 43 62 1 4 46 47 64 60 1 4 49 51 57 60 1 4 16 43 44 59 1 4 16 39 43 59 1 4 57 60 64 63 1 4 7 14 36 42 1 4 33 53 65 57 1 4 15 26 62 39 1 4 33 34 37 59 1 4 33 34 59 38 1 4 47 60 63 64 1 4 7 27 42 36 1 4 13 17 24 41 1 4 13 24 55 41 1 4 46 60 64 62 1 4 41 43 62 59 1 4 57 58 64 61 1 4 9 33 65 38 1 4 18 26 46 62 1 4 16 38 39 59 1 4 19 49 56 63 1 4 24 41 64 55 1 4 8 13 17 24 1 4 25 39 40 62 1 4 11 54 56 58 1 4 29 30 60 48 1 4 3 11 58 31 1 4 5 23 47 63 1 4 31 50 53 58 1 4 32 52 65 53 1 4 28 34 44 45 1 4 34 44 45 59 1 4 57 60 62 64 1 4 19 23 63 56 1 4 14 41 61 42 1 4 20 49 50 58 1 4 41 42 45 61 1 4 31 33 58 53 1 4 33 57 61 58 1 4 27 28 45 37 1 4 28 34 45 37 # surfid 0 p1 p2 trignum1 trignum2 domin/surfnr1 domout/surfnr2 ednr1 dist1 ednr2 dist2 edgesegmentsgi2 72 1 0 1 9 -1 -1 1 7 1 0 0 0 2 0 9 1 -1 -1 1 7 1 0 0 0 1 0 9 10 -1 -1 1 7 1 0 0 0 2 0 10 9 -1 -1 1 7 1 0 0 0 1 0 10 4 -1 -1 1 7 1 0 0 0 2 0 4 10 -1 -1 1 7 1 0 0 0 1 0 11 3 -1 -1 8 1 2 0 0 0 3 0 3 11 -1 -1 8 1 2 0 0 0 1 0 12 11 -1 -1 8 1 2 0 0 0 3 0 11 12 -1 -1 8 1 2 0 0 0 1 0 7 12 -1 -1 8 1 2 0 0 0 3 0 12 7 -1 -1 8 1 2 0 0 0 4 0 8 13 -1 -1 4 8 3 0 0 0 3 0 13 8 -1 -1 4 8 3 0 0 0 4 0 13 14 -1 -1 4 8 3 0 0 0 3 0 14 13 -1 -1 4 8 3 0 0 0 4 0 14 7 -1 -1 4 8 3 0 0 0 3 0 7 14 -1 -1 4 8 3 0 0 0 4 0 15 6 -1 -1 7 4 4 0 0 0 2 0 6 15 -1 -1 7 4 4 0 0 0 4 0 16 15 -1 -1 7 4 4 0 0 0 2 0 15 16 -1 -1 7 4 4 0 0 0 4 0 4 16 -1 -1 7 4 4 0 0 0 2 0 16 4 -1 -1 7 4 4 0 0 0 5 0 8 17 -1 -1 2 4 5 0 0 0 4 0 17 8 -1 -1 2 4 5 0 0 0 5 0 17 18 -1 -1 2 4 5 0 0 0 4 0 18 17 -1 -1 2 4 5 0 0 0 5 0 18 6 -1 -1 2 4 5 0 0 0 4 0 6 18 -1 -1 2 4 5 0 0 0 6 0 19 5 -1 -1 8 3 6 0 0 0 3 0 5 19 -1 -1 8 3 6 0 0 0 6 0 20 19 -1 -1 8 3 6 0 0 0 3 0 19 20 -1 -1 8 3 6 0 0 0 6 0 3 20 -1 -1 8 3 6 0 0 0 3 0 20 3 -1 -1 8 3 6 0 0 0 6 0 2 21 -1 -1 3 7 7 0 0 0 2 0 21 2 -1 -1 3 7 7 0 0 0 6 0 21 22 -1 -1 3 7 7 0 0 0 2 0 22 21 -1 -1 3 7 7 0 0 0 6 0 22 1 -1 -1 3 7 7 0 0 0 2 0 1 22 -1 -1 3 7 7 0 0 0 5 0 5 23 -1 -1 2 8 8 0 0 0 3 0 23 5 -1 -1 2 8 8 0 0 0 5 0 23 24 -1 -1 2 8 8 0 0 0 3 0 24 23 -1 -1 2 8 8 0 0 0 5 0 24 8 -1 -1 2 8 8 0 0 0 3 0 8 24 -1 -1 2 8 8 0 0 0 5 0 25 2 -1 -1 7 2 9 0 0 0 2 0 2 25 -1 -1 7 2 9 0 0 0 5 0 26 25 -1 -1 7 2 9 0 0 0 2 0 25 26 -1 -1 7 2 9 0 0 0 5 0 6 26 -1 -1 7 2 9 0 0 0 2 0 26 6 -1 -1 7 2 9 0 0 0 1 0 27 7 -1 -1 4 1 10 0 0 0 4 0 7 27 -1 -1 4 1 10 0 0 0 1 0 28 27 -1 -1 4 1 10 0 0 0 4 0 27 28 -1 -1 4 1 10 0 0 0 1 0 4 28 -1 -1 4 1 10 0 0 0 4 0 28 4 -1 -1 4 1 10 0 0 0 5 0 29 5 -1 -1 3 2 11 0 0 0 6 0 5 29 -1 -1 3 2 11 0 0 0 5 0 30 29 -1 -1 3 2 11 0 0 0 6 0 29 30 -1 -1 3 2 11 0 0 0 5 0 2 30 -1 -1 3 2 11 0 0 0 6 0 30 2 -1 -1 3 2 11 0 0 0 1 0 3 31 -1 -1 1 3 12 0 0 0 6 0 31 3 -1 -1 1 3 12 0 0 0 1 0 31 32 -1 -1 1 3 12 0 0 0 6 0 32 31 -1 -1 1 3 12 0 0 0 1 0 32 1 -1 -1 1 3 12 0 0 0 6 0 1 32 -1 -1 1 3 12 0 0 0 # X Y Z points 65 0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000 0.3333333333333333 0.0000000000000000 0.0000000000000000 0.6666666666666666 0.0000000000000000 1.0000000000000000 0.3333333333333333 0.0000000000000000 1.0000000000000000 0.6666666666666666 0.0000000000000000 1.0000000000000000 1.0000000000000000 0.6666666666666666 1.0000000000000000 1.0000000000000000 0.3333333333333332 0.0000000000000000 1.0000000000000000 0.6666666666666666 0.0000000000000000 1.0000000000000000 0.3333333333333332 0.6666666666666666 1.0000000000000000 1.0000000000000000 0.3333333333333332 1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000 0.6666666666666666 1.0000000000000000 0.0000000000000000 0.3333333333333332 0.0000000000000000 0.0000000000000000 0.6666666666666666 0.0000000000000000 0.0000000000000000 0.3333333333333332 1.0000000000000000 0.3333333333333333 1.0000000000000000 1.0000000000000000 0.6666666666666666 1.0000000000000000 0.0000000000000000 0.3333333333333333 1.0000000000000000 0.0000000000000000 0.6666666666666666 1.0000000000000000 0.6666666666666666 1.0000000000000000 0.0000000000000000 0.3333333333333332 1.0000000000000000 0.0000000000000000 0.6666666666666666 0.0000000000000000 1.0000000000000000 0.3333333333333332 0.0000000000000000 1.0000000000000000 0.6666666666666666 0.0000000000000000 0.0000000000000000 0.3333333333333332 0.0000000000000000 0.0000000000000000 0.3453764872152520 0.4289616495406477 0.0000000000000000 0.2363722957339057 0.7629978630944177 0.0000000000000000 0.7093903868425258 0.4777271339652773 0.0000000000000000 0.7767853874295251 0.7740629504580570 0.0000000000000000 0.5093916952832738 0.7373846519656869 0.0000000000000000 0.0000000000000000 0.5848322921574791 0.2973390248238796 0.0000000000000000 0.6376771832790789 0.6256884212430072 0.0000000000000000 0.3078273776201016 0.4901690889415314 0.6546235127847480 1.0000000000000000 0.5710383504593523 0.7636277042660942 1.0000000000000000 0.2370021369055823 0.2906096131574742 1.0000000000000000 0.5222728660347228 0.2232146125704748 1.0000000000000000 0.2259370495419430 0.4906083047167261 1.0000000000000000 0.2626153480343131 0.5226154526972956 0.6723847618372673 1.0000000000000000 0.7303054535238108 0.3470956979891270 1.0000000000000000 0.3846043860484825 0.3457533069880933 1.0000000000000000 0.6545492698511188 0.0000000000000000 0.5710115507028192 0.7635147493753501 0.0000000000000000 0.2370411648783929 0.2904642514608775 0.0000000000000000 0.5222189640348618 0.2231265594790997 0.0000000000000000 0.2258767298015257 0.4905217481815927 0.0000000000000000 0.2626047101435547 1.0000000000000000 0.5848322921574791 0.2973390248238796 1.0000000000000000 0.6376771832790789 0.6256884212430072 1.0000000000000000 0.3078273776201016 0.4901690889415314 0.4272276804008159 0.3426052995823172 0.4176406498588326 0.7299469195459262 0.2730082184471636 0.2789191388190804 0.3202369865656342 0.7063322531411742 0.4178510398137523 0.4187321713884653 0.2791900408384976 0.7467956942298275 0.6883019035327874 0.6532015011171384 0.3389153362395730 0.2848826858717337 0.6291905246270143 0.7492446890085234 0.7505520006346695 0.2364072052628841 0.7265283730519375 0.6904080728530597 0.5313023561184044 0.6778821530260029 0.2153574046463540 0.2182196460363049 0.2340094009251045 # pnum index pointelements 0 identifications 15 1 3 1 2 5 1 4 7 1 6 8 1 9 11 1 10 12 1 15 13 1 16 14 1 21 19 1 22 20 1 25 23 1 26 24 1 38 54 1 39 55 1 40 56 1 identificationtypes 1 2 bcnames 6 1 outer 2 default 3 default 4 outer 5 outer 6 outer # Surfnr Red Green Blue face_colours 6 1 0.00000000 1.00000000 0.00000000 7 0.00000000 1.00000000 0.00000000 8 0.00000000 1.00000000 0.00000000 4 0.00000000 1.00000000 0.00000000 2 0.00000000 1.00000000 0.00000000 3 0.00000000 1.00000000 0.00000000 endmesh csgsurfaces 8 plane 6 -1.00000000 0.00000000 0.00000000 0.00000000 0.00000000 -1.00000000 plane 6 -1.00000000 0.00000000 1.00000000 0.00000000 0.00000000 1.00000000 plane 6 -1.00000000 0.00000000 0.00000000 0.00000000 -1.00000000 0.00000000 plane 6 -1.00000000 1.00000000 0.00000000 0.00000000 1.00000000 0.00000000 plane 6 -1.00000000 0.00000000 0.00000000 -1.00000000 0.00000000 0.00000000 plane 6 2.00000000 0.00000000 0.00000000 1.00000000 0.00000000 0.00000000 plane 6 0.00000000 0.00000000 0.00000000 -1.00000000 0.00000000 0.00000000 plane 6 1.00000000 0.00000000 0.00000000 1.00000000 0.00000000 0.00000000 tests/meshes/neuroglancer/000077500000000000000000000000001456244072500162015ustar00rootroot00000000000000tests/meshes/neuroglancer/simple1000066400000000000000000000001441456244072500174750ustar00rootroot00000000000000?@@@???@@?@@@@@?tests/meshes/obj/000077500000000000000000000000001456244072500142675ustar00rootroot00000000000000tests/meshes/obj/elephav.obj000066400000000000000000002262001456244072500164110ustar00rootroot00000000000000v 58.853138 435.746368 437.847656 v 61.271862 446.228241 451.650909 v 45.632473 438.882446 448.876190 v 43.213753 428.400574 435.072937 v 56.434418 425.264465 424.044373 v 72.073807 432.610260 426.819092 v 74.492523 443.092133 440.622375 v 77.634003 404.993622 487.831390 v 63.959820 396.794891 486.676514 v 62.973885 384.242767 476.827179 v 75.662132 379.889404 468.132751 v 89.336319 388.088135 469.287659 v 90.322258 400.640259 479.136963 v 93.682159 376.787689 529.558960 v 82.148361 368.697540 529.924622 v 82.322182 355.907349 524.009094 v 94.029808 351.207306 517.727844 v 105.563606 359.297455 517.362183 v 105.389778 372.087646 523.277710 v 108.411240 360.555664 572.781372 v 99.024544 353.304565 574.287476 v 99.969086 341.678589 571.660583 v 110.300323 337.303680 567.527466 v 119.687019 344.554749 566.021362 v 118.742477 356.180725 568.648254 v 121.222130 354.367249 614.419189 v 113.883820 348.399292 616.557678 v 115.199722 338.796143 616.260925 v 123.853928 335.160919 613.825684 v 131.192230 341.128876 611.687195 v 129.876343 350.732056 611.983948 v 131.857529 355.871368 652.373718 v 126.408997 351.363708 654.638306 v 127.757248 344.134491 655.665466 v 134.554031 341.412994 654.428040 v 140.002563 345.920685 652.163391 v 138.654312 353.149872 651.136230 v 140.319107 362.644165 685.414490 v 136.569427 359.567688 687.388794 v 137.706100 354.674377 688.867554 v 142.592468 352.857605 688.372009 v 146.342163 355.934113 686.397705 v 145.205475 360.827393 684.918945 v 148.206787 371.175720 717.345581 vn -0.894299 0.378740 0.238297 vn -0.870790 0.373891 0.319266 vn -0.863918 0.479090 0.155298 vn -0.859066 0.080675 0.505468 vn -0.842871 0.351905 0.407101 vn -0.841280 -0.539357 -0.036639 vn -0.811197 0.308039 0.497062 vn -0.801667 -0.593358 0.072500 vn -0.777164 0.238562 0.582327 vn -0.777007 -0.579595 -0.245620 vn -0.766805 -0.615762 0.181239 vn -0.763096 -0.465091 0.448748 vn -0.737972 -0.613192 0.281768 vn -0.715424 -0.593006 0.369476 vn -0.272647 0.788640 -0.551099 vn -0.164455 0.983456 -0.075955 vn -0.118487 0.989085 0.087592 vn -0.080297 0.975665 -0.204036 vn -0.071552 0.641900 0.763442 vn -0.062678 0.961212 0.268595 vn -0.054639 -0.798021 -0.600148 vn 0.001993 0.888912 0.458074 vn 0.022093 -0.918925 -0.393813 vn 0.072954 0.762930 0.642351 vn 0.086181 -0.675437 -0.732365 vn 0.090718 -0.978638 -0.184493 vn 0.123058 -0.915326 0.383452 vn 0.148480 -0.988840 0.012206 vn 0.194573 -0.962975 0.186604 vn 0.207306 0.361286 0.909118 vn 0.745477 0.614181 -0.258932 vn 0.767884 0.614205 -0.181954 vn 0.791763 0.545023 0.275794 vn 0.794751 0.599140 -0.096961 vn 0.796167 -0.273029 -0.539975 vn 0.805985 0.526979 -0.269596 vn 0.825648 0.564131 -0.007864 vn 0.835943 -0.337450 -0.432814 vn 0.859478 0.504963 0.079437 vn 0.871544 -0.368786 -0.323123 vn 0.872663 -0.115109 -0.474562 vn 0.901383 -0.373176 -0.219654 vn 0.908108 -0.418051 0.023938 vn 0.924977 -0.357868 -0.127861 s off f 1//15 3//15 2//15 f 1//15 4//15 3//15 f 1//15 5//15 4//15 f 1//15 6//15 5//15 f 1//15 7//15 6//15 f 1//15 2//15 7//15 f 2//19 9//9 8//24 f 2//19 3//4 9//9 f 3//4 10//6 9//9 f 3//4 4//10 10//6 f 4//10 11//21 10//6 f 4//10 5//25 11//21 f 5//25 12//35 11//21 f 5//25 6//41 12//35 f 6//41 13//39 12//35 f 6//41 7//33 13//39 f 7//33 8//24 13//39 f 7//33 2//19 8//24 f 8//24 15//7 14//22 f 8//24 9//9 15//7 f 9//9 16//8 15//7 f 9//9 10//6 16//8 f 10//6 17//23 16//8 f 10//6 11//21 17//23 f 11//21 18//38 17//23 f 11//21 12//35 18//38 f 12//35 19//37 18//38 f 12//35 13//39 19//37 f 13//39 14//22 19//37 f 13//39 8//24 14//22 f 14//22 21//5 20//20 f 14//22 15//7 21//5 f 15//7 22//11 21//5 f 15//7 16//8 22//11 f 16//8 23//26 22//11 f 16//8 17//23 23//26 f 17//23 24//40 23//26 f 17//23 18//38 24//40 f 18//38 25//34 24//40 f 18//38 19//37 25//34 f 19//37 20//20 25//34 f 19//37 14//22 20//20 f 20//20 27//2 26//17 f 20//20 21//5 27//2 f 21//5 28//13 27//2 f 21//5 22//11 28//13 f 22//11 29//28 28//13 f 22//11 23//26 29//28 f 23//26 30//42 29//28 f 23//26 24//40 30//42 f 24//40 31//32 30//42 f 24//40 25//34 31//32 f 25//34 26//17 31//32 f 25//34 20//20 26//17 f 26//17 33//1 32//16 f 26//17 27//2 33//1 f 27//2 34//14 33//1 f 27//2 28//13 34//14 f 28//13 35//29 34//14 f 28//13 29//28 35//29 f 29//28 36//44 35//29 f 29//28 30//42 36//44 f 30//42 37//31 36//44 f 30//42 31//32 37//31 f 31//32 32//16 37//31 f 31//32 26//17 32//16 f 32//16 39//3 38//18 f 32//16 33//1 39//3 f 33//1 40//12 39//3 f 33//1 34//14 40//12 f 34//14 41//27 40//12 f 34//14 35//29 41//27 f 35//29 42//43 41//27 f 35//29 36//44 42//43 f 36//44 43//36 42//43 f 36//44 37//31 43//36 f 37//31 38//18 43//36 f 37//31 32//16 38//18 f 44//30 38//18 39//3 f 44//30 39//3 40//12 f 44//30 40//12 41//27 f 44//30 41//27 42//43 f 44//30 42//43 43//36 f 44//30 43//36 38//18 v -58.853138 435.746368 437.847656 v -61.271862 446.228241 451.650909 v -45.632473 438.882446 448.876190 v -43.213753 428.400574 435.072937 v -56.434422 425.264465 424.044373 v -72.073807 432.610260 426.819092 v -74.492523 443.092133 440.622375 v -77.634003 404.993622 487.831390 v -63.959824 396.794891 486.676514 v -62.973885 384.242767 476.827179 v -75.662140 379.889404 468.132751 v -89.336327 388.088135 469.287659 v -90.322258 400.640259 479.136963 v -93.682159 376.787689 529.558960 v -82.148361 368.697540 529.924622 v -82.322189 355.907349 524.009094 v -94.029808 351.207306 517.727844 v -105.563606 359.297455 517.362183 v -105.389778 372.087646 523.277710 v -108.411240 360.555664 572.781372 v -99.024551 353.304565 574.287476 v -99.969093 341.678589 571.660583 v -110.300323 337.303650 567.527466 v -119.687019 344.554749 566.021362 v -118.742477 356.180725 568.648254 v -121.222130 354.367249 614.419189 v -113.883820 348.399292 616.557678 v -115.199722 338.796112 616.260925 v -123.853928 335.160919 613.825684 v -131.192230 341.128876 611.687195 v -129.876343 350.732056 611.983948 v -131.857529 355.871368 652.373657 v -126.408997 351.363678 654.638306 v -127.757248 344.134491 655.665466 v -134.554031 341.412964 654.428040 v -140.002563 345.920654 652.163391 v -138.654312 353.149872 651.136230 v -140.319107 362.644165 685.414490 v -136.569427 359.567688 687.388794 v -137.706085 354.674377 688.867554 v -142.592468 352.857605 688.372009 v -146.342163 355.934113 686.397705 v -145.205475 360.827362 684.918945 v -148.206787 371.175720 717.345581 vn -0.924977 -0.357868 -0.127862 vn -0.908108 -0.418051 0.023938 vn -0.901383 -0.373176 -0.219654 vn -0.872663 -0.115109 -0.474562 vn -0.871544 -0.368786 -0.323123 vn -0.859478 0.504963 0.079437 vn -0.835943 -0.337450 -0.432814 vn -0.825648 0.564131 -0.007864 vn -0.805985 0.526979 -0.269596 vn -0.796167 -0.273029 -0.539975 vn -0.794751 0.599140 -0.096961 vn -0.791763 0.545023 0.275794 vn -0.767884 0.614205 -0.181954 vn -0.745477 0.614181 -0.258932 vn -0.207305 0.361286 0.909119 vn -0.194573 -0.962975 0.186604 vn -0.148480 -0.988840 0.012206 vn -0.123058 -0.915326 0.383452 vn -0.090718 -0.978638 -0.184494 vn -0.086181 -0.675437 -0.732365 vn -0.072954 0.762930 0.642351 vn -0.022092 -0.918925 -0.393813 vn -0.001993 0.888912 0.458074 vn 0.054639 -0.798021 -0.600148 vn 0.062678 0.961212 0.268595 vn 0.071552 0.641900 0.763442 vn 0.080297 0.975665 -0.204036 vn 0.118487 0.989085 0.087592 vn 0.164455 0.983456 -0.075955 vn 0.272647 0.788640 -0.551099 vn 0.715424 -0.593006 0.369476 vn 0.737972 -0.613192 0.281768 vn 0.763097 -0.465091 0.448748 vn 0.766805 -0.615762 0.181239 vn 0.777007 -0.579595 -0.245620 vn 0.777164 0.238562 0.582327 vn 0.801667 -0.593358 0.072500 vn 0.811197 0.308039 0.497062 vn 0.841280 -0.539357 -0.036639 vn 0.842871 0.351905 0.407101 vn 0.859066 0.080675 0.505468 vn 0.863918 0.479091 0.155298 vn 0.870790 0.373891 0.319266 vn 0.894299 0.378740 0.238297 s off f 47//74 45//74 46//74 f 48//74 45//74 47//74 f 49//74 45//74 48//74 f 50//74 45//74 49//74 f 51//74 45//74 50//74 f 46//74 45//74 51//74 f 53//80 46//70 52//65 f 47//85 46//70 53//80 f 54//83 47//85 53//80 f 48//79 47//85 54//83 f 55//68 48//79 54//83 f 49//64 48//79 55//68 f 56//54 49//64 55//68 f 50//48 49//64 56//54 f 57//50 50//48 56//54 f 51//56 50//48 57//50 f 52//65 51//56 57//50 f 46//70 51//56 52//65 f 59//82 52//65 58//67 f 53//80 52//65 59//82 f 60//81 53//80 59//82 f 54//83 53//80 60//81 f 61//66 54//83 60//81 f 55//68 54//83 61//66 f 62//51 55//68 61//66 f 56//54 55//68 62//51 f 63//52 56//54 62//51 f 57//50 56//54 63//52 f 58//67 57//50 63//52 f 52//65 57//50 58//67 f 65//84 58//67 64//69 f 59//82 58//67 65//84 f 66//78 59//82 65//84 f 60//81 59//82 66//78 f 67//63 60//81 66//78 f 61//66 60//81 67//63 f 68//49 61//66 67//63 f 62//51 61//66 68//49 f 69//55 62//51 68//49 f 63//52 62//51 69//55 f 64//69 63//52 69//55 f 58//67 63//52 64//69 f 71//87 64//69 70//72 f 65//84 64//69 71//87 f 72//76 65//84 71//87 f 66//78 65//84 72//76 f 73//61 66//78 72//76 f 67//63 66//78 73//61 f 74//47 67//63 73//61 f 68//49 67//63 74//47 f 75//57 68//49 74//47 f 69//55 68//49 75//57 f 70//72 69//55 75//57 f 64//69 69//55 70//72 f 77//88 70//72 76//73 f 71//87 70//72 77//88 f 78//75 71//87 77//88 f 72//76 71//87 78//75 f 79//60 72//76 78//75 f 73//61 72//76 79//60 f 80//45 73//61 79//60 f 74//47 73//61 80//45 f 81//58 74//47 80//45 f 75//57 74//47 81//58 f 76//73 75//57 81//58 f 70//72 75//57 76//73 f 83//86 76//73 82//71 f 77//88 76//73 83//86 f 84//77 77//88 83//86 f 78//75 77//88 84//77 f 85//62 78//75 84//77 f 79//60 78//75 85//62 f 86//46 79//60 85//62 f 80//45 79//60 86//46 f 87//53 80//45 86//46 f 81//58 80//45 87//53 f 82//71 81//58 87//53 f 76//73 81//58 82//71 f 82//71 88//59 83//86 f 83//86 88//59 84//77 f 84//77 88//59 85//62 f 85//62 88//59 86//46 f 86//46 88//59 87//53 f 87//53 88//59 82//71 v 0.0 674.705322 144.186432 v 0.0 659.442139 21.519569 v 0.0 680.494873 -114.901505 v 0.0 677.588013 -209.343933 v 0.0 662.451782 -253.749756 v 0.0 619.927368 -307.605072 v 0.0 306.693176 -355.725189 v 0.0 282.978760 -335.986023 v 0.0 386.651550 -381.947906 v 0.0 452.129333 -373.061371 v 0.0 464.639008 -375.535736 v 0.0 548.165222 -365.281372 v 0.0 518.615662 -399.860443 v 0.0 487.902100 -415.659485 v 0.0 470.975586 -417.727692 v 0.0 412.627502 -416.541016 v 0.0 420.618774 -400.237640 v 0.0 468.681763 -389.056061 v 0.0 470.368866 -385.914642 v 0.0 400.649750 232.339508 v 0.0 347.050842 206.288391 v 0.0 325.252075 178.899506 v 0.0 313.806885 117.932831 v 0.0 314.837463 137.754272 v 0.0 319.189819 159.624985 v 0.0 269.879456 -59.536957 v 0.0 282.266632 -6.034477 v 0.0 297.798676 51.131927 v 0.0 260.412598 -228.332947 v 0.0 358.095825 -417.698120 v 0.0 358.767883 -407.076111 v 0.0 320.548431 -416.855591 v 0.0 320.728119 -408.190948 v 0.0 264.678802 -402.953827 v 0.0 264.655396 -410.283264 v 0.0 222.839462 -394.393463 v 0.0 220.736511 -402.430603 v 0.0 194.609314 -395.416138 v 0.0 195.844925 -389.740295 v 0.0 590.681274 457.055023 v 0.0 640.005554 429.823761 v 0.0 679.878784 348.259949 v 0.0 668.416504 190.709930 v 0.0 652.424377 233.459885 v 0.0 651.805298 253.958023 v 0.0 680.161011 329.351013 v 0.0 428.164734 323.170593 v 0.0 400.098724 454.754395 v 0.0 406.014984 256.838745 v 0.0 421.577759 269.887939 v 0.0 663.574707 285.522308 v 0.0 191.588745 -393.203400 v 0.0 192.143539 -389.721771 v 0.0 190.525833 -391.550476 v 0.0 410.218842 379.853394 v 0.0 365.601990 426.700714 v 0.0 384.466461 414.494141 v 3.499443 362.597076 435.303223 v 0.0 360.711639 437.529083 v 0.0 358.145355 433.967712 v 0.0 359.026581 431.397980 v 0.0 359.140442 436.638733 v 0.0 372.866119 423.227142 v 0.0 408.493378 434.260864 v 28.561386 680.828491 152.769043 v 89.147934 617.291870 8.004128 v 96.425346 630.883789 -225.567169 v 116.623894 563.952209 189.125305 v 135.253036 498.373596 -205.083496 v 102.284485 378.783508 48.076321 v 68.635033 167.411774 -317.269745 v 96.345901 507.969360 -346.729340 v 31.685234 491.952789 -389.875305 v 10.539116 450.210785 -412.170105 v 14.840648 470.856445 -392.668488 v 9.770735 472.211578 -386.184265 v 116.521805 178.172684 154.520325 v 101.803406 173.197296 113.135895 v 55.110474 461.715881 228.562622 v 29.197432 416.091888 232.177322 v 54.124645 341.445679 204.883423 v 22.852367 323.534698 168.565872 v 84.888359 269.782104 -192.991913 v 47.324020 200.793472 -307.052338 v 29.879377 260.380920 -316.286987 v 20.908667 256.221558 -244.277130 v 62.163719 156.204163 -253.238617 v 62.163738 176.986816 173.840515 v 56.963161 169.769424 121.614166 v 43.459377 310.782928 57.872765 v 83.565216 2.812408 87.586609 v 119.566643 53.798767 153.346359 v 120.825768 27.622589 189.236847 v 132.673050 32.518005 172.354477 v 100.340591 57.047668 168.625092 v 35.022182 3.596130 114.613876 v 49.711658 51.683380 162.079895 v 48.979992 13.613007 192.654083 v 80.733612 25.959442 204.418716 v 126.390030 2.812408 102.117195 v 129.353973 2.812408 183.618622 v 80.694801 2.812408 207.141617 v 109.345688 2.812408 201.640762 v 54.500790 2.812408 197.025269 v 37.963989 2.812408 156.271210 v 139.499969 2.812408 146.296692 v 3.631164 358.617462 -409.063477 v 57.757877 427.477478 486.621735 v 66.305794 450.091858 460.693939 v 72.430794 460.165649 446.856262 v 47.409939 647.614136 276.093872 v 36.704021 552.561401 468.196411 v 83.166336 462.374969 282.517426 v 97.794746 548.457275 427.954742 v 72.193176 537.422913 451.219727 v 68.373138 426.302185 310.172607 v 77.928581 491.388367 391.080841 v 77.033066 517.108643 416.937897 v 95.374550 515.711792 392.263123 v 105.212822 520.682190 367.848602 v 87.732895 523.537720 399.655945 v 84.234589 524.386841 406.262543 v 84.769745 431.200195 461.652008 v 57.775162 414.015961 490.634369 v 74.483322 462.666901 387.797546 v 83.963806 439.915405 441.301392 v 55.741165 407.134583 490.437347 v 48.314449 391.637878 482.220612 v 39.757469 395.107086 481.343567 v 101.927597 524.532593 289.449036 v 82.183266 594.307739 237.627914 v 71.702682 671.114136 371.912689 v 119.746429 630.880615 313.814209 v 98.411400 565.605469 308.700073 v 79.552818 657.672974 319.828979 v 97.803490 662.251343 369.554565 v 105.080696 646.188416 367.574463 v 117.992828 633.772278 360.118774 v 79.021889 666.386292 376.674713 v 124.450096 299.812317 86.423988 v 93.567039 287.448730 69.341545 v 78.712456 171.689362 96.333069 v 87.672211 515.497437 404.092529 v 142.125198 487.190826 75.761795 v 54.375797 387.937256 444.369385 v 85.685417 409.201599 479.704407 v 75.063766 396.528595 444.140350 v 72.064491 403.284302 486.151031 v 55.174248 386.216644 471.262787 v 92.361580 598.479614 358.234436 v 87.489281 406.573090 463.900604 v 82.037880 406.060242 475.072571 v 84.995010 402.431366 455.035065 v 74.360077 397.155579 449.641205 v 63.094547 391.059723 453.824066 v 72.155159 402.082642 479.629272 v 64.321938 394.400360 477.144409 v 60.365757 388.976166 466.250458 v 1.504729 192.970337 -391.704651 v 26.869917 399.271179 427.409149 v 7.880798 375.080566 429.976166 v 0.0 519.736877 501.326874 v 65.431923 471.750336 453.331879 v 59.693134 486.968262 469.050507 v 49.102673 503.374390 485.327179 v 0.0 394.447510 473.427734 v 0.0 271.682587 -127.661087 v 0.0 275.780365 -180.105072 v 0.0 269.623871 -203.846863 v 0.0 259.270508 -244.079498 v 0.0 263.265289 -283.019745 v 0.0 269.925720 -317.727051 v 109.488457 53.266907 111.529510 v 84.580719 50.753479 94.974091 v 50.518833 50.401581 114.022522 v 134.554459 368.699158 177.532349 v 101.841042 55.608490 -266.554230 v 98.785851 2.812439 -321.523987 v 91.762856 53.266937 -312.111664 v 82.614990 57.047699 -244.255707 v 91.918777 164.786652 -267.169952 v 91.037750 165.903214 -304.247284 v 52.195866 52.106079 -328.667084 v 65.839615 2.812439 -336.054565 v 114.947449 32.518036 -251.286713 v 121.774368 2.812439 -277.344482 v 111.628372 2.812439 -240.022552 v 103.100166 27.622620 -234.404327 v 91.620087 2.812439 -222.000397 v 63.008007 25.959473 -219.222443 v 20.238386 2.812439 -267.369965 v 31.986055 51.683411 -253.584595 v 26.654669 2.812439 -309.027313 v 31.254389 13.613037 -230.987091 v 36.775185 2.812439 -226.615906 v 62.969196 2.812439 -216.499542 v 32.038773 52.228394 -309.618652 v 126.084244 371.670807 -159.708084 v 139.331024 364.170563 -280.618439 v 129.495178 357.771454 -216.346008 v 178.559692 521.329956 -125.311584 v 50.741852 379.704468 -369.854065 v 126.098862 491.326019 -299.065491 v 25.699888 85.600800 -308.335480 v 39.776405 673.907227 331.222168 v 77.348427 578.127563 439.451477 v 0.0 389.291992 486.090851 v 53.197598 417.579498 504.358887 v 0.0 330.902405 571.212524 v 0.0 396.047028 561.760254 v 0.0 448.367249 543.600098 v 0.0 321.122803 506.096130 v 0.0 366.578491 493.328552 v 0.0 380.585266 487.656494 v 0.0 267.242859 572.588379 v 0.0 264.636108 514.555420 v 0.0 211.547058 566.812988 v 0.0 214.041687 515.471313 v 0.0 163.338455 556.453003 v 0.0 168.880386 511.701508 v 0.0 123.445633 543.892090 v 0.0 128.865707 504.205658 v 0.0 88.772095 529.737183 v 0.0 95.004730 494.096680 v 0.0 60.432281 512.184814 v 0.0 76.766418 484.694214 v 0.0 44.941895 485.530060 v 0.0 67.669769 470.122314 v 0.0 41.181000 460.585022 v 0.0 66.030304 456.359985 v 0.0 46.149750 438.815735 v 0.0 67.915985 446.862457 v 0.0 50.750610 425.787476 v 0.0 71.117798 439.923950 v 0.0 53.089813 422.642944 v 0.0 71.009399 436.437805 v 0.0 55.499329 424.193329 v 0.0 69.540802 436.470398 v 40.318222 323.123749 514.340576 v 44.910927 374.415741 507.571686 v 35.962704 330.110870 547.104858 v 39.266464 389.826355 539.846375 v 39.321838 436.194061 526.118530 v 42.576550 379.890869 485.175507 v 35.673855 364.374329 490.916351 v 32.409584 320.630798 503.137512 v 31.128992 262.814819 516.546265 v 31.120661 267.396942 550.957947 v 26.104368 212.173584 516.899048 v 26.217802 214.731186 547.603699 v 21.585955 166.665604 513.017090 v 21.755678 165.012177 540.377319 v 17.811789 128.329285 505.388031 v 18.029829 127.116852 530.179321 v 14.884996 95.121552 494.605957 v 15.121249 92.141266 516.896851 v 13.721362 76.612671 484.731659 v 13.961364 67.320435 502.436493 v 12.503607 67.766357 469.977448 v 12.746117 54.042847 480.469910 v 11.684473 66.317017 456.185638 v 11.929141 50.868683 459.775146 v 11.238026 69.033691 446.305969 v 11.482570 54.426880 442.698792 v 11.532056 71.943146 439.734772 v 11.768776 57.081177 435.891022 v 10.756892 71.728729 436.944397 v 11.010005 58.284698 433.492401 v 9.039405 69.993774 437.114563 v 9.558839 58.987793 434.598755 v 112.880119 371.152161 -355.810730 v -3.499443 362.597076 435.303223 v -28.561386 680.828491 152.769043 v -89.147926 617.291870 8.004128 v -96.425339 630.883789 -225.567169 v -116.623886 563.952209 189.125305 v -135.253036 498.373596 -205.083496 v -102.284477 378.783508 48.076321 v -68.635025 167.411774 -317.269745 v -96.345894 507.969360 -346.729340 v -31.685234 491.952789 -389.875305 v -10.539116 450.210785 -412.170105 v -14.840648 470.856445 -392.668488 v -9.770735 472.211578 -386.184265 v -116.521797 178.172684 154.520325 v -101.803398 173.197296 113.135895 v -55.110477 461.715881 228.562622 v -29.197432 416.091888 232.177322 v -54.124649 341.445679 204.883423 v -22.852367 323.534698 168.565872 v -84.888351 269.782104 -192.991913 v -47.324024 200.793472 -307.052338 v -29.879377 260.380920 -316.286987 v -20.908667 256.221558 -244.277130 v -62.163723 156.204163 -253.238617 v -62.163742 176.986816 173.840515 v -56.963165 169.769424 121.614166 v -43.459381 310.782928 57.872765 v -83.565208 2.812408 87.586609 v -119.566635 53.798767 153.346359 v -120.825760 27.622589 189.236847 v -132.673050 32.518005 172.354477 v -100.340584 57.047668 168.625092 v -35.022186 3.596130 114.613876 v -49.711662 51.683380 162.079895 v -48.979996 13.613007 192.654083 v -80.733604 25.959442 204.418716 v -126.390022 2.812408 102.117195 v -129.353973 2.812408 183.618622 v -80.694794 2.812408 207.141617 v -109.345680 2.812408 201.640762 v -54.500793 2.812408 197.025269 v -37.963993 2.812408 156.271210 v -139.499969 2.812408 146.296692 v -3.631164 358.617462 -409.063477 v -57.757881 427.477478 486.621735 v -66.305786 450.091858 460.693939 v -72.430786 460.165649 446.856262 v -47.409943 647.614136 276.093872 v -36.704025 552.561401 468.196411 v -83.166328 462.374969 282.517426 v -97.794739 548.457275 427.954742 v -72.193169 537.422913 451.219727 v -68.373131 426.302185 310.172607 v -77.928574 491.388367 391.080841 v -77.033058 517.108643 416.937897 v -95.374542 515.711792 392.263123 v -105.212814 520.682190 367.848602 v -87.732887 523.537720 399.655945 v -84.234581 524.386841 406.262543 v -84.769737 431.200195 461.652008 v -57.775166 414.015961 490.634369 v -74.483315 462.666901 387.797546 v -83.963799 439.915405 441.301392 v -55.741169 407.134583 490.437347 v -48.314453 391.637878 482.220612 v -39.757473 395.107086 481.343567 v -101.927589 524.532593 289.449036 v -82.183258 594.307739 237.627914 v -71.702675 671.114136 371.912689 v -119.746422 630.880615 313.814209 v -98.411392 565.605469 308.700073 v -79.552811 657.672974 319.828979 v -97.803482 662.251343 369.554565 v -105.080688 646.188416 367.574463 v -117.992821 633.772278 360.118774 v -79.021881 666.386292 376.674713 v -124.450089 299.812317 86.423988 v -93.567032 287.448730 69.341545 v -78.712448 171.689362 96.333069 v -87.672203 515.497437 404.092529 v -142.125198 487.190826 75.761795 v -54.375801 387.937256 444.369385 v -85.685410 409.201599 479.704407 v -75.063759 396.528595 444.140350 v -72.064484 403.284302 486.151031 v -55.174252 386.216644 471.262787 v -92.361572 598.479614 358.234436 v -87.489273 406.573090 463.900604 v -82.037872 406.060242 475.072571 v -84.995003 402.431366 455.035065 v -74.360069 397.155579 449.641205 v -63.094551 391.059723 453.824066 v -72.155151 402.082642 479.629272 v -64.321930 394.400360 477.144409 v -60.365761 388.976166 466.250458 v -1.504729 192.970337 -391.704651 v -26.869917 399.271179 427.409149 v -7.880797 375.080566 429.976166 v -65.431915 471.750336 453.331879 v -59.693138 486.968262 469.050507 v -49.102676 503.374390 485.327179 v -109.488449 53.266907 111.529510 v -84.580711 50.753479 94.974091 v -50.518837 50.401581 114.022522 v -134.554459 368.699158 177.532349 v -101.841034 55.608490 -266.554230 v -98.785835 2.812439 -321.523987 v -91.762848 53.266937 -312.111664 v -82.614983 57.047699 -244.255707 v -91.918770 164.786652 -267.169952 v -91.037743 165.903214 -304.247284 v -52.195869 52.106079 -328.667084 v -65.839607 2.812439 -336.054565 v -114.947441 32.518036 -251.286713 v -121.774361 2.812439 -277.344482 v -111.628365 2.812439 -240.022552 v -103.100159 27.622620 -234.404327 v -91.620079 2.812439 -222.000397 v -63.008011 25.959473 -219.222443 v -20.238386 2.812439 -267.369965 v -31.986055 51.683411 -253.584595 v -26.654669 2.812439 -309.027313 v -31.254389 13.613037 -230.987091 v -36.775188 2.812439 -226.615906 v -62.969200 2.812439 -216.499542 v -32.038776 52.228394 -309.618652 v -126.084236 371.670807 -159.708084 v -139.331024 364.170563 -280.618439 v -129.495178 357.771454 -216.346008 v -178.559692 521.329956 -125.311584 v -50.741856 379.704468 -369.854065 v -126.098854 491.326019 -299.065491 v -25.699888 85.600800 -308.335480 v -39.776409 673.907227 331.222168 v -77.348419 578.127563 439.451477 v -53.197601 417.579498 504.358887 v -40.318226 323.123749 514.340576 v -44.910931 374.415741 507.571686 v -35.962708 330.110870 547.104858 v -39.266468 389.826355 539.846375 v -39.321842 436.194061 526.118530 v -42.576553 379.890869 485.175507 v -35.673859 364.374329 490.916351 v -32.409588 320.630798 503.137512 v -31.128992 262.814819 516.546265 v -31.120661 267.396942 550.957947 v -26.104368 212.173584 516.899048 v -26.217802 214.731186 547.603699 v -21.585955 166.665604 513.017090 v -21.755678 165.012177 540.377319 v -17.811789 128.329285 505.388031 v -18.029829 127.116852 530.179321 v -14.884996 95.121552 494.605957 v -15.121249 92.141266 516.896851 v -13.721362 76.612671 484.731659 v -13.961364 67.320435 502.436493 v -12.503607 67.766357 469.977448 v -12.746117 54.042847 480.469910 v -11.684473 66.317017 456.185638 v -11.929141 50.868683 459.775146 v -11.238026 69.033691 446.305969 v -11.482570 54.426880 442.698792 v -11.532056 71.943146 439.734772 v -11.768776 57.081177 435.891022 v -10.756892 71.728729 436.944397 v -11.010005 58.284698 433.492401 v -9.039405 69.993774 437.114563 v -9.558839 58.987793 434.598755 v -112.880112 371.152161 -355.810730 v 83.166336 462.374969 282.517426 v 97.803490 662.251343 369.554565 v 79.021889 666.386292 376.674713 v 71.702682 671.114136 371.912689 v 86.375710 688.534546 351.013245 v 71.041710 678.234863 364.105988 v 89.965607 597.799927 316.320465 v 98.411423 565.605469 308.700073 v 101.927597 524.532593 289.449036 v 223.745453 617.214966 252.629211 v 263.779053 603.554077 111.231125 v 250.851547 565.993835 117.612213 v 250.153976 692.800903 231.157837 v 119.746429 625.196045 322.051086 v 105.080696 646.188416 367.574463 v 154.985229 658.576416 332.510071 v 200.347290 698.369263 295.631378 v 229.934494 703.016418 255.213852 v 174.806488 714.569336 301.024475 v 124.796967 690.498535 335.785156 v 117.839737 696.844116 329.868256 v 95.352585 457.567444 275.603210 v 96.982460 444.826904 269.866760 v 234.951843 542.151672 122.796227 v 94.138756 428.036285 264.856140 v 100.976105 401.472992 242.941208 v 136.378464 448.177368 250.506012 v 165.012772 528.794556 247.697281 v 211.981293 523.431274 131.970963 v 117.992828 633.772278 360.118774 v 273.383362 653.040894 132.604462 v 266.934570 628.560059 118.617035 v 246.283127 699.169312 221.285507 v 208.589951 710.134399 260.576599 v 181.199646 712.553772 272.422424 v 162.155991 711.845215 282.709442 v 149.180008 711.340088 296.747589 v 132.867691 703.030273 309.399963 v 99.128807 374.954041 230.420349 v 126.651459 384.494080 220.204956 v 144.220947 395.410858 207.701462 v 173.386261 448.508972 173.954041 v 190.554718 464.418640 167.773285 v 194.502914 488.440857 151.411835 v -83.166328 462.374969 282.517426 v -97.803482 662.251343 369.554565 v -79.021881 666.386292 376.674713 v -71.702675 671.114136 371.912689 v -86.375702 688.534546 351.013245 v -71.041702 678.234863 364.105988 v -89.965599 597.799927 316.320465 v -98.411415 565.605469 308.700073 v -101.927589 524.532593 289.449036 v -223.745453 617.214966 252.629211 v -263.779053 603.554077 111.231125 v -250.851547 565.993835 117.612213 v -250.153976 692.800903 231.157837 v -119.746422 625.196045 322.051086 v -105.080688 646.188416 367.574463 v -154.985229 658.576416 332.510071 v -200.347290 698.369263 295.631378 v -229.934494 703.016418 255.213852 v -174.806488 714.569336 301.024475 v -124.796959 690.498535 335.785156 v -117.839729 696.844116 329.868256 v -95.352577 457.567444 275.603210 v -96.982452 444.826904 269.866760 v -234.951843 542.151672 122.796227 v -94.138748 428.036285 264.856140 v -100.976097 401.472992 242.941208 v -136.378464 448.177368 250.506012 v -165.012772 528.794556 247.697281 v -211.981293 523.431274 131.970963 v -117.992821 633.772278 360.118774 v -273.383362 653.040894 132.604462 v -266.934570 628.560059 118.617035 v -246.283127 699.169312 221.285507 v -208.589951 710.134399 260.576599 v -181.199646 712.553772 272.422424 v -162.155991 711.845215 282.709442 v -149.180008 711.340088 296.747589 v -132.867691 703.030273 309.399963 v -99.128799 374.954041 230.420349 v -126.651451 384.494080 220.204956 v -144.220947 395.410858 207.701462 v -173.386261 448.508972 173.954041 v -190.554718 464.418640 167.773285 v -194.502914 488.440857 151.411835 v 0.0 54.705750 448.371765 v 142.979660 432.121704 53.944386 v 142.259354 433.763885 -188.649475 v 172.123810 430.795349 -110.045517 v -142.979660 432.121704 53.944386 v -172.123810 430.795349 -110.045517 v -143.964798 430.321655 -184.622345 vn -0.998673 -0.034541 -0.038197 vn -0.990649 0.135951 -0.011452 vn -0.987159 -0.127900 -0.095699 vn -0.986500 -0.119607 -0.111860 vn -0.986100 0.044479 0.160089 vn -0.984962 0.117969 0.126225 vn -0.979778 0.191800 -0.056995 vn -0.977198 -0.212138 0.009060 vn -0.976428 0.050032 0.209963 vn -0.976178 -0.053752 -0.210207 vn -0.975949 -0.212540 0.048483 vn -0.973460 0.072270 0.217146 vn -0.972644 0.041816 0.228505 vn -0.970849 -0.239674 0.003057 vn -0.969837 -0.181013 0.163249 vn -0.968383 -0.136717 -0.208669 vn -0.966751 -0.112059 0.229859 vn -0.965052 -0.262008 -0.005160 vn -0.962143 0.263665 -0.069009 vn -0.958495 0.285041 0.006183 vn -0.953528 0.272774 -0.127976 vn -0.949830 0.173022 -0.260551 vn -0.948489 0.053494 0.312262 vn -0.947053 -0.260579 -0.187587 vn -0.946600 0.082869 -0.311578 vn -0.938748 -0.026743 0.343566 vn -0.937868 -0.104277 0.330952 vn -0.935929 -0.286619 0.204664 vn -0.935098 -0.331743 -0.124651 vn -0.932268 -0.235072 0.274985 vn -0.931502 -0.303009 0.201219 vn -0.929509 0.363013 0.065076 vn -0.928884 -0.235037 -0.286238 vn -0.925893 -0.317985 -0.203981 vn -0.924696 0.071256 0.373979 vn -0.916991 -0.031325 -0.397675 vn -0.916435 0.259058 0.305016 vn -0.915159 0.092329 0.392376 vn -0.914811 -0.319057 -0.247637 vn -0.914078 0.078569 -0.397854 vn -0.911128 0.354633 -0.209953 vn -0.908375 -0.067055 -0.412744 vn -0.906057 0.381196 -0.183714 vn -0.904557 -0.348274 0.245931 vn -0.903638 -0.241643 0.353620 vn -0.902406 -0.409772 -0.133235 vn -0.900933 -0.428188 -0.070534 vn -0.900115 -0.427563 0.083560 vn -0.898403 -0.437664 0.036353 vn -0.897638 -0.075175 0.434275 vn -0.896492 -0.209997 0.390132 vn -0.896375 -0.314013 0.312901 vn -0.895561 0.279921 0.345853 vn -0.891660 -0.206380 -0.402927 vn -0.890179 0.379752 0.251732 vn -0.888577 -0.176965 0.423219 vn -0.887054 0.129180 -0.443224 vn -0.886106 -0.134553 0.443521 vn -0.885226 0.027722 0.464334 vn -0.884238 -0.118708 0.451699 vn -0.882303 -0.157757 0.443457 vn -0.878000 0.112721 -0.465200 vn -0.873920 -0.146801 0.463372 vn -0.873196 -0.371001 0.316049 vn -0.872924 -0.457451 -0.169535 vn -0.870805 -0.189656 -0.453573 vn -0.870593 -0.091603 0.483401 vn -0.865869 -0.474897 0.157301 vn -0.861154 0.276771 0.426395 vn -0.856864 -0.108272 0.504044 vn -0.855800 -0.253704 0.450823 vn -0.855330 -0.234309 0.462072 vn -0.849413 -0.298478 0.435210 vn -0.847413 -0.078917 -0.525036 vn -0.843182 -0.013413 0.537461 vn -0.843031 0.385436 0.375151 vn -0.838528 0.241794 -0.488268 vn -0.835554 -0.085150 0.542770 vn -0.833203 -0.240931 -0.497720 vn -0.832966 0.065493 0.549434 vn -0.823581 0.337742 0.455680 vn -0.817464 0.436860 0.375374 vn -0.814548 0.371365 0.445644 vn -0.811590 -0.255527 0.525383 vn -0.809905 -0.331436 0.483946 vn -0.803584 -0.038763 -0.593929 vn -0.800903 -0.377041 0.465182 vn -0.794084 -0.471906 0.383061 vn -0.792189 -0.309116 0.526198 vn -0.788328 0.002355 0.615251 vn -0.788092 0.067491 0.611846 vn -0.781838 0.285062 -0.554498 vn -0.777567 -0.591815 -0.212471 vn -0.775315 -0.577158 -0.256467 vn -0.774406 0.368873 -0.514031 vn -0.771773 -0.380859 0.509228 vn -0.770790 0.159652 -0.616761 vn -0.758194 -0.073472 -0.647876 vn -0.755487 -0.312193 0.576000 vn -0.754149 -0.399642 0.521101 vn -0.746151 -0.546448 0.380334 vn -0.732123 0.095479 -0.674448 vn -0.730965 0.274824 0.624629 vn -0.730829 -0.166424 -0.661961 vn -0.728164 0.013960 -0.685261 vn -0.724982 -0.054737 -0.686590 vn -0.721317 0.603325 0.340147 vn -0.721087 0.206756 -0.661275 vn -0.718620 0.395565 -0.571939 vn -0.714578 -0.279688 0.641212 vn -0.713958 -0.007352 0.700150 vn -0.713845 0.236036 0.659327 vn -0.709469 0.632278 -0.311253 vn -0.704546 -0.685447 -0.183788 vn -0.704485 0.708344 0.044158 vn -0.701339 0.712586 -0.018544 vn -0.694846 -0.065323 0.716185 vn -0.692512 -0.077725 0.717207 vn -0.690065 0.161488 -0.705501 vn -0.689580 0.170597 0.703830 vn -0.686426 0.664631 -0.295102 vn -0.685608 0.004560 0.727956 vn -0.682386 0.138034 0.717841 vn -0.680992 0.698217 0.220777 vn -0.675654 -0.072406 -0.733655 vn -0.670901 0.738451 0.067690 vn -0.656495 0.224532 0.720138 vn -0.652418 -0.127716 0.747020 vn -0.644505 0.292579 -0.706407 vn -0.640390 -0.454265 -0.619309 vn -0.636597 0.765415 0.094257 vn -0.616919 0.311126 0.722919 vn -0.600800 0.705010 0.376829 vn -0.600603 -0.329338 0.728568 vn -0.574344 0.747302 0.334169 vn -0.572946 -0.632493 0.521235 vn -0.559577 -0.603300 0.568244 vn -0.556795 0.328822 0.762795 vn -0.553084 -0.509467 0.659197 vn -0.547534 -0.107099 0.829902 vn -0.545461 0.374907 0.749612 vn -0.535228 0.398782 0.744650 vn -0.532780 -0.476055 -0.699655 vn -0.530867 -0.827856 0.181201 vn -0.521236 0.243999 -0.817788 vn -0.517433 -0.420395 0.745340 vn -0.508450 0.393580 0.765881 vn -0.495364 -0.234143 0.836535 vn -0.484867 -0.794204 0.366256 vn -0.473621 -0.880617 0.014049 vn -0.472804 0.574982 -0.667722 vn -0.472291 -0.334673 -0.815436 vn -0.471354 -0.828010 -0.303685 vn -0.469107 0.831646 -0.297160 vn -0.468301 -0.857556 0.212820 vn -0.461319 -0.405063 0.789372 vn -0.450325 -0.446152 0.773406 vn -0.444120 -0.444711 0.777811 vn -0.441887 -0.256146 0.859724 vn -0.439407 -0.322907 0.838244 vn -0.438683 -0.408483 0.800437 vn -0.436358 -0.325835 0.838703 vn -0.434279 -0.884435 0.170809 vn -0.434080 0.379053 0.817247 vn -0.425709 -0.891134 -0.157008 vn -0.422963 -0.243408 -0.872843 vn -0.419890 -0.903209 -0.088916 vn -0.412971 -0.223117 0.882991 vn -0.406686 0.162694 0.898965 vn -0.394028 0.533409 0.748477 vn -0.388126 -0.854167 0.346059 vn -0.386568 -0.751703 -0.534329 vn -0.359381 -0.254884 -0.897708 vn -0.357518 0.435442 0.826179 vn -0.338292 0.932448 0.126886 vn -0.329682 0.816620 -0.473753 vn -0.309872 0.472052 0.825316 vn -0.299902 0.730850 0.613121 vn -0.296168 -0.790144 0.536616 vn -0.254041 0.759104 0.599353 vn -0.252111 0.965555 0.064372 vn -0.241052 -0.956433 -0.164712 vn -0.227466 -0.968585 -0.100511 vn -0.211146 0.950518 -0.227889 vn -0.209784 0.962537 0.171794 vn -0.208099 -0.117171 -0.971064 vn -0.198014 -0.950206 -0.240623 vn -0.193781 0.067335 -0.978731 vn -0.189832 0.701031 0.687400 vn -0.189713 0.142783 0.971402 vn -0.168066 0.721925 0.671251 vn -0.148919 0.976646 0.154874 vn -0.140819 -0.956507 -0.255470 vn -0.137971 0.198536 -0.970334 vn -0.122026 -0.411153 0.903362 vn -0.114623 0.951038 0.287033 vn -0.099176 0.991926 -0.079033 vn -0.073506 0.159810 -0.984407 vn -0.065433 -0.255417 -0.964614 vn -0.064541 -0.090827 -0.993773 vn -0.058920 -0.900096 -0.431689 vn -0.052794 0.743146 0.667044 vn -0.047591 0.467261 0.882838 vn -0.044326 0.093986 -0.994586 vn -0.042800 0.389630 0.919977 vn -0.041113 0.739929 0.671428 vn -0.024351 -0.992009 0.123795 vn -0.022340 -0.180099 -0.983395 vn -0.019868 -0.225351 0.974075 vn -0.013558 0.600072 -0.799831 vn -0.010605 0.997301 -0.072650 vn -0.008578 -0.999963 -0.000008 vn -0.008367 0.905320 0.424648 vn -0.006112 -0.999819 0.018014 vn -0.005719 -0.999984 -0.000005 vn -0.002208 -0.999991 -0.003606 vn 0.0 -1.0 0.0 vn 0.0 -0.999976 -0.006993 vn 0.0 -0.999889 -0.014906 vn 0.0 -0.999882 0.015391 vn 0.0 -0.999327 0.036671 vn 0.0 -0.998639 -0.052165 vn 0.0 -0.996705 0.081117 vn 0.0 -0.996120 0.088002 vn 0.0 -0.995823 -0.091305 vn 0.0 -0.995316 0.096677 vn 0.0 -0.992374 -0.123261 vn 0.0 -0.991705 -0.128537 vn 0.0 -0.987873 0.155261 vn 0.0 -0.983513 -0.180835 vn 0.0 -0.976630 0.214929 vn 0.0 -0.972219 0.234074 vn 0.0 -0.968848 0.247658 vn 0.0 -0.968741 0.248072 vn 0.0 -0.965647 -0.259856 vn 0.0 -0.953782 0.300501 vn 0.0 -0.942680 -0.333697 vn 0.0 -0.931168 -0.364591 vn 0.0 -0.923728 0.383050 vn 0.0 -0.918268 -0.395960 vn 0.0 -0.907019 -0.421089 vn 0.0 -0.899311 0.437310 vn 0.0 -0.897831 0.440340 vn 0.0 -0.889807 0.456337 vn 0.0 -0.869472 0.493982 vn 0.0 -0.809618 -0.586957 vn 0.0 -0.747858 0.663859 vn 0.0 -0.746748 0.665107 vn 0.0 -0.729334 -0.684158 vn 0.0 -0.691000 -0.722855 vn 0.0 -0.661306 0.750116 vn 0.0 -0.646505 -0.762910 vn 0.0 -0.643279 -0.765632 vn 0.0 -0.625114 0.780533 vn 0.0 -0.617650 0.786453 vn 0.0 -0.571180 -0.820825 vn 0.0 -0.541665 -0.840594 vn 0.0 -0.519853 -0.854256 vn 0.0 -0.468728 -0.883343 vn 0.0 -0.459639 -0.888106 vn 0.0 -0.441129 0.897444 vn 0.0 -0.411495 0.911412 vn 0.0 -0.411394 -0.911458 vn 0.0 -0.354066 -0.935220 vn 0.0 -0.341915 -0.939731 vn 0.0 -0.336356 0.941735 vn 0.0 -0.320303 -0.947315 vn 0.0 -0.257187 -0.966362 vn 0.0 -0.239983 0.970777 vn 0.0 -0.239735 0.970838 vn 0.0 -0.226535 -0.974003 vn 0.0 -0.206544 0.978437 vn 0.0 -0.161062 0.986944 vn 0.0 -0.148290 0.988944 vn 0.0 -0.144077 -0.989567 vn 0.0 -0.114550 -0.993418 vn 0.0 -0.069705 0.997568 vn 0.0 -0.059938 -0.998202 vn 0.0 -0.039081 -0.999236 vn 0.0 -0.030054 -0.999548 vn 0.0 -0.024487 0.999700 vn 0.0 0.046255 -0.998930 vn 0.0 0.048086 -0.998843 vn 0.0 0.082046 0.996629 vn 0.0 0.084064 0.996460 vn 0.0 0.151835 -0.988406 vn 0.0 0.248054 -0.968746 vn 0.0 0.252961 0.967476 vn 0.0 0.258139 -0.966108 vn 0.0 0.264014 0.964519 vn 0.0 0.288674 -0.957427 vn 0.0 0.377903 -0.925845 vn 0.0 0.406244 -0.913765 vn 0.0 0.434964 0.900448 vn 0.0 0.489355 0.872085 vn 0.0 0.499338 -0.866407 vn 0.0 0.510465 0.859898 vn 0.0 0.613714 0.789529 vn 0.0 0.652702 -0.757614 vn 0.0 0.707194 -0.707019 vn 0.0 0.745702 -0.666280 vn 0.0 0.878826 -0.477143 vn 0.0 0.900083 -0.435718 vn 0.0 0.929260 -0.369426 vn 0.0 0.931024 -0.364957 vn 0.0 0.940177 0.340687 vn 0.0 0.950652 0.310260 vn 0.0 0.966604 -0.256273 vn 0.0 0.969453 0.245278 vn 0.0 0.983536 -0.180712 vn 0.0 0.985018 -0.172454 vn 0.0 0.989641 0.143563 vn 0.0 0.993286 0.115684 vn 0.0 0.993555 0.113353 vn 0.0 0.996990 -0.077533 vn 0.0 0.997817 0.066047 vn 0.0 0.999991 0.004262 vn 0.002208 -0.999991 -0.003606 vn 0.005719 -0.999984 -0.000005 vn 0.006112 -0.999819 0.018014 vn 0.008367 0.905320 0.424648 vn 0.008578 -0.999963 -0.000008 vn 0.010605 0.997301 -0.072650 vn 0.013558 0.600072 -0.799831 vn 0.019868 -0.225351 0.974075 vn 0.022340 -0.180099 -0.983395 vn 0.024351 -0.992009 0.123795 vn 0.041113 0.739929 0.671428 vn 0.042800 0.389630 0.919977 vn 0.044326 0.093986 -0.994586 vn 0.047591 0.467261 0.882838 vn 0.052794 0.743146 0.667044 vn 0.058920 -0.900096 -0.431689 vn 0.064541 -0.090827 -0.993773 vn 0.065433 -0.255417 -0.964614 vn 0.073506 0.159810 -0.984407 vn 0.099176 0.991926 -0.079033 vn 0.114623 0.951038 0.287033 vn 0.122026 -0.411153 0.903362 vn 0.137971 0.198536 -0.970334 vn 0.140819 -0.956507 -0.255470 vn 0.148919 0.976646 0.154874 vn 0.168066 0.721925 0.671251 vn 0.189713 0.142783 0.971402 vn 0.189832 0.701031 0.687400 vn 0.193781 0.067335 -0.978731 vn 0.198014 -0.950206 -0.240623 vn 0.208099 -0.117171 -0.971064 vn 0.209784 0.962537 0.171794 vn 0.211146 0.950518 -0.227889 vn 0.227466 -0.968585 -0.100511 vn 0.241052 -0.956433 -0.164712 vn 0.252111 0.965555 0.064372 vn 0.254041 0.759104 0.599353 vn 0.296168 -0.790144 0.536616 vn 0.299902 0.730850 0.613121 vn 0.309872 0.472052 0.825316 vn 0.329682 0.816620 -0.473753 vn 0.338292 0.932448 0.126886 vn 0.357518 0.435442 0.826179 vn 0.359381 -0.254883 -0.897708 vn 0.386568 -0.751703 -0.534329 vn 0.388126 -0.854167 0.346059 vn 0.394028 0.533409 0.748477 vn 0.406686 0.162694 0.898965 vn 0.412971 -0.223117 0.882991 vn 0.419890 -0.903209 -0.088916 vn 0.422963 -0.243408 -0.872843 vn 0.425709 -0.891134 -0.157008 vn 0.434080 0.379053 0.817247 vn 0.434279 -0.884435 0.170809 vn 0.436358 -0.325835 0.838703 vn 0.438683 -0.408483 0.800437 vn 0.439407 -0.322907 0.838244 vn 0.441887 -0.256146 0.859724 vn 0.444120 -0.444711 0.777811 vn 0.450325 -0.446152 0.773406 vn 0.461319 -0.405063 0.789372 vn 0.468301 -0.857556 0.212820 vn 0.469107 0.831646 -0.297160 vn 0.471354 -0.828010 -0.303685 vn 0.472291 -0.334673 -0.815436 vn 0.472804 0.574982 -0.667722 vn 0.473621 -0.880617 0.014049 vn 0.484867 -0.794204 0.366256 vn 0.495365 -0.234143 0.836535 vn 0.508450 0.393580 0.765881 vn 0.517433 -0.420395 0.745340 vn 0.521236 0.243999 -0.817788 vn 0.530867 -0.827856 0.181201 vn 0.532780 -0.476055 -0.699655 vn 0.535228 0.398782 0.744650 vn 0.545461 0.374907 0.749612 vn 0.547533 -0.107099 0.829902 vn 0.553084 -0.509467 0.659197 vn 0.556795 0.328822 0.762795 vn 0.559577 -0.603300 0.568244 vn 0.572946 -0.632493 0.521235 vn 0.574344 0.747302 0.334169 vn 0.600603 -0.329338 0.728568 vn 0.600800 0.705010 0.376829 vn 0.616919 0.311126 0.722919 vn 0.636597 0.765415 0.094257 vn 0.640390 -0.454265 -0.619309 vn 0.644505 0.292579 -0.706407 vn 0.652418 -0.127716 0.747020 vn 0.656495 0.224532 0.720138 vn 0.670901 0.738451 0.067690 vn 0.675654 -0.072406 -0.733654 vn 0.680992 0.698217 0.220777 vn 0.682386 0.138034 0.717841 vn 0.685608 0.004560 0.727956 vn 0.686426 0.664631 -0.295102 vn 0.689580 0.170597 0.703830 vn 0.690065 0.161488 -0.705501 vn 0.692512 -0.077725 0.717207 vn 0.694846 -0.065323 0.716185 vn 0.701339 0.712586 -0.018544 vn 0.704485 0.708344 0.044158 vn 0.704546 -0.685447 -0.183788 vn 0.709469 0.632278 -0.311253 vn 0.713845 0.236036 0.659327 vn 0.713958 -0.007352 0.700150 vn 0.714578 -0.279688 0.641212 vn 0.718620 0.395565 -0.571939 vn 0.721087 0.206756 -0.661275 vn 0.721317 0.603325 0.340147 vn 0.724982 -0.054737 -0.686590 vn 0.728164 0.013960 -0.685261 vn 0.730829 -0.166424 -0.661961 vn 0.730965 0.274824 0.624629 vn 0.732123 0.095479 -0.674448 vn 0.746151 -0.546448 0.380334 vn 0.754149 -0.399642 0.521101 vn 0.755487 -0.312193 0.576000 vn 0.758194 -0.073472 -0.647876 vn 0.770790 0.159652 -0.616761 vn 0.771773 -0.380859 0.509228 vn 0.774406 0.368873 -0.514031 vn 0.775315 -0.577158 -0.256467 vn 0.777567 -0.591815 -0.212471 vn 0.781838 0.285062 -0.554498 vn 0.788092 0.067491 0.611846 vn 0.788328 0.002355 0.615251 vn 0.792189 -0.309115 0.526198 vn 0.794084 -0.471906 0.383061 vn 0.800903 -0.377041 0.465182 vn 0.803584 -0.038763 -0.593929 vn 0.809905 -0.331436 0.483946 vn 0.811590 -0.255527 0.525383 vn 0.814548 0.371365 0.445644 vn 0.817465 0.436860 0.375374 vn 0.823581 0.337742 0.455680 vn 0.832966 0.065493 0.549435 vn 0.833203 -0.240931 -0.497720 vn 0.835554 -0.085150 0.542770 vn 0.838528 0.241794 -0.488268 vn 0.843031 0.385436 0.375151 vn 0.843182 -0.013413 0.537461 vn 0.847413 -0.078917 -0.525036 vn 0.849413 -0.298478 0.435210 vn 0.855330 -0.234309 0.462072 vn 0.855800 -0.253704 0.450823 vn 0.856864 -0.108272 0.504044 vn 0.861154 0.276771 0.426395 vn 0.865869 -0.474897 0.157301 vn 0.870593 -0.091603 0.483401 vn 0.870805 -0.189656 -0.453574 vn 0.872924 -0.457451 -0.169535 vn 0.873196 -0.371001 0.316049 vn 0.873920 -0.146801 0.463372 vn 0.878000 0.112721 -0.465200 vn 0.882303 -0.157757 0.443457 vn 0.884238 -0.118708 0.451699 vn 0.885226 0.027722 0.464334 vn 0.886106 -0.134553 0.443521 vn 0.887054 0.129180 -0.443224 vn 0.888577 -0.176965 0.423219 vn 0.890179 0.379752 0.251732 vn 0.891660 -0.206380 -0.402927 vn 0.895561 0.279921 0.345853 vn 0.896375 -0.314013 0.312901 vn 0.896492 -0.209997 0.390132 vn 0.897638 -0.075175 0.434275 vn 0.900115 -0.427563 0.083560 vn 0.900933 -0.428188 -0.070534 vn 0.902406 -0.409772 -0.133235 vn 0.903523 -0.427444 0.030629 vn 0.903638 -0.241643 0.353620 vn 0.904557 -0.348274 0.245931 vn 0.906057 0.381196 -0.183714 vn 0.908375 -0.067055 -0.412744 vn 0.911128 0.354633 -0.209953 vn 0.914078 0.078569 -0.397854 vn 0.914811 -0.319057 -0.247637 vn 0.915159 0.092329 0.392376 vn 0.916435 0.259058 0.305016 vn 0.916991 -0.031325 -0.397675 vn 0.924696 0.071256 0.373979 vn 0.925893 -0.317986 -0.203981 vn 0.928884 -0.235037 -0.286238 vn 0.929509 0.363012 0.065076 vn 0.931502 -0.303009 0.201219 vn 0.932268 -0.235072 0.274985 vn 0.935406 -0.329436 -0.128401 vn 0.937868 -0.104277 0.330952 vn 0.938748 -0.026743 0.343566 vn 0.940622 -0.271350 0.203960 vn 0.946846 0.079474 -0.311717 vn 0.947053 -0.260578 -0.187587 vn 0.948489 0.053494 0.312262 vn 0.950649 0.170929 -0.258938 vn 0.953528 0.272774 -0.127976 vn 0.958495 0.285041 0.006183 vn 0.962143 0.263665 -0.069009 vn 0.965052 -0.262008 -0.005160 vn 0.966751 -0.112059 0.229859 vn 0.968383 -0.136717 -0.208669 vn 0.969837 -0.181013 0.163249 vn 0.970849 -0.239674 0.003057 vn 0.972644 0.041816 0.228505 vn 0.973460 0.072270 0.217146 vn 0.975949 -0.212540 0.048483 vn 0.976178 -0.053752 -0.210207 vn 0.976428 0.050032 0.209963 vn 0.977198 -0.212138 0.009060 vn 0.979778 0.191800 -0.056995 vn 0.984962 0.117969 0.126225 vn 0.986100 0.044479 0.160089 vn 0.987794 -0.105965 -0.114172 vn 0.988213 -0.121405 -0.093246 vn 0.990649 0.135951 -0.011452 vn 0.998673 -0.034541 -0.038197 vn 1.0 0.0 0.0 s off f 149//334 146//554 148//309 f 146//554 150//336 148//309 f 146//554 147//360 150//336 f 149//334 144//344 146//554 f 151//346 249//492 144//344 f 154//507 90//403 153//447 f 90//403 154//507 91//404 f 155//501 93//390 92//398 f 155//501 94//388 93//390 f 232//616 154//507 156//569 f 89//405 153//447 90//403 f 91//404 154//507 155//501 f 155//501 92//398 91//404 f 155//501 160//477 94//388 f 165//572 228//568 264//544 f 286//576 158//528 171//451 f 289//615 154//507 232//616 f 289//615 157//597 155//501 f 171//451 175//228 269//559 f 155//501 291//600 160//477 f 359//497 287//619 270//548 f 286//576 171//451 288//596 f 98//351 160//477 97//368 f 359//497 159//288 290//423 f 160//477 359//497 290//423 f 290//423 172//154 173//260 f 161//543 98//351 164//439 f 98//351 161//543 160//477 f 101//384 100//387 161//543 f 102//375 162//536 103//370 f 162//536 104//367 103//370 f 100//387 160//477 161//543 f 160//477 100//387 94//388 f 101//384 162//536 102//375 f 161//543 162//536 101//384 f 104//367 162//536 195//605 f 118//364 104//367 195//605 f 163//483 195//605 162//536 f 164//439 163//483 161//543 f 162//536 161//543 163//483 f 195//605 163//483 105//361 f 106//335 105//361 163//483 f 107//306 106//335 164//439 f 163//483 164//439 106//335 f 107//306 164//439 99//341 f 228//568 165//572 166//524 f 180//590 188//527 261//525 f 229//449 228//568 230//296 f 228//568 229//449 618//598 f 178//421 158//528 229//449 f 108//343 169//427 168//486 f 169//427 108//343 109//342 f 170//267 169//427 110//330 f 109//342 110//330 169//427 f 176//216 165//572 169//427 f 111//318 178//421 177//121 f 112//332 177//121 176//216 f 170//267 113//322 112//332 f 255//310 256//312 171//451 f 171//451 114//314 255//310 f 171//451 115//320 114//314 f 110//330 113//322 170//267 f 116//321 178//421 111//318 f 115//320 178//421 116//321 f 171//451 178//421 115//320 f 257//324 171//451 256//312 f 174//251 172//154 175//228 f 173//260 172//154 174//251 f 171//451 174//251 175//228 f 174//251 257//324 117//319 f 258//307 174//251 117//319 f 259//315 174//251 258//307 f 173//260 174//251 259//315 f 173//260 259//315 260//328 f 173//260 260//328 96//340 f 171//451 257//324 174//251 f 176//216 183//445 165//572 f 177//121 178//421 230//296 f 166//524 261//525 262//418 f 111//318 177//121 112//332 f 176//216 170//267 112//332 f 179//428 262//418 261//525 f 178//421 229//449 230//296 f 170//267 176//216 169//427 f 168//486 169//427 167//538 f 98//351 99//341 164//439 f 179//428 261//525 188//527 f 180//590 182//540 194//603 f 189//542 194//603 182//540 f 183//445 181//480 182//540 f 181//480 191//453 189//542 f 181//480 189//542 182//540 f 181//480 183//445 187//291 f 193//101 185//171 184//165 f 187//291 185//171 186//208 f 192//205 186//208 193//101 f 187//291 183//445 185//171 f 190//278 187//291 186//208 f 186//208 192//205 190//278 f 193//101 186//208 185//171 f 181//480 187//291 191//453 f 191//453 187//291 190//278 f 189//305 191//305 194//305 f 190//305 192//305 193//304 f 193//304 191//305 190//305 f 194//305 191//305 193//304 f 184//300 179//302 188//303 f 193//304 184//300 188//303 f 193//304 188//303 194//305 f 180//590 194//603 188//527 f 182//540 180//590 183//445 f 165//572 180//590 261//525 f 183//445 180//590 165//572 f 262//418 179//428 184//165 f 263//145 184//165 185//171 f 184//165 263//145 262//418 f 185//171 183//445 176//216 f 118//364 195//605 121//358 f 195//605 105//361 119//365 f 121//358 120//622 118//364 f 195//605 119//365 121//358 f 121//358 123//622 120//622 f 122//622 123//622 121//358 f 123//622 122//622 124//378 f 124//378 125//363 123//622 f 125//363 124//378 247//611 f 247//611 126//348 125//363 f 127//372 247//611 124//378 f 167//538 169//427 264//544 f 219//579 167//538 156//569 f 231//563 206//561 252//584 f 294//475 128//385 200//458 f 89//405 131//397 153//447 f 132//395 153//447 131//397 f 219//579 133//393 199//446 f 133//393 139//392 199//446 f 250//383 200//458 128//385 f 203//532 200//458 253//490 f 202//549 200//458 203//532 f 213//588 204//457 201//557 f 203//532 206//561 202//549 f 205//591 208//607 207//562 f 202//549 210//551 209//552 f 206//561 231//563 210//551 f 207//562 209//552 231//563 f 211//567 214//620 197//541 f 211//567 234//522 239//604 f 214//620 198//585 197//541 f 213//588 198//585 214//620 f 196//519 211//567 197//541 f 205//591 198//585 213//588 f 213//588 214//620 235//529 f 211//567 196//519 234//522 f 236//465 234//522 196//519 f 215//535 236//465 212//511 f 196//519 212//511 236//465 f 204//457 138//317 201//557 f 138//317 204//457 135//313 f 254//325 136//316 217//281 f 133//393 219//579 132//395 f 201//557 219//579 218//612 f 219//579 201//557 167//538 f 168//486 167//538 201//557 f 201//557 138//317 168//486 f 168//486 138//317 137//333 f 137//333 108//343 168//486 f 153//447 219//579 156//569 f 219//579 153//447 132//395 f 264//544 169//427 165//572 f 129//386 220//437 130//400 f 199//446 139//392 293//438 f 219//579 221//581 222//621 f 222//621 218//612 219//579 f 220//437 224//489 223//468 f 224//489 225//515 223//468 f 199//446 293//438 223//468 f 293//438 220//437 223//468 f 293//438 130//400 220//437 f 221//581 225//515 226//610 f 221//581 199//446 223//468 f 199//446 221//581 219//579 f 294//475 225//515 129//386 f 224//489 227//444 129//386 f 227//444 220//437 129//386 f 294//475 202//549 226//610 f 232//616 228//568 618//598 f 228//568 166//524 230//296 f 252//584 206//561 203//532 f 231//563 205//591 207//562 f 231//563 252//584 251//599 f 210//551 202//549 206//561 f 228//568 232//616 264//544 f 171//451 158//528 178//421 f 217//281 136//316 237//415 f 233//435 237//415 152//331 f 237//415 216//440 217//281 f 215//535 216//440 236//465 f 237//415 245//473 216//440 f 236//465 216//440 245//473 f 222//621 221//581 238//608 f 238//608 208//607 222//621 f 218//612 222//621 208//607 f 208//607 238//608 202//549 f 218//612 208//607 201//557 f 201//557 208//607 205//591 f 226//610 202//549 238//608 f 238//608 221//581 226//610 f 294//475 226//610 225//515 f 225//515 224//489 129//386 f 208//607 202//549 209//552 f 209//552 207//562 208//607 f 240//467 239//604 234//522 f 239//604 241//580 211//567 f 241//580 214//620 211//567 f 241//580 242//508 214//620 f 235//529 214//620 242//508 f 233//435 235//529 242//508 f 242//508 243//455 233//435 f 234//522 236//465 244//478 f 244//478 240//467 234//522 f 243//455 246//472 233//435 f 237//415 233//435 246//472 f 245//473 237//415 246//472 f 236//465 245//473 244//478 f 247//611 140//337 126//348 f 247//611 127//372 141//350 f 140//337 247//611 142//311 f 247//611 141//350 142//311 f 156//569 154//507 153//447 f 289//615 618//598 620//593 f 204//457 213//588 248//469 f 135//313 204//457 143//326 f 204//457 248//469 143//326 f 143//326 248//469 145//338 f 146//554 249//492 248//469 f 145//338 248//469 249//492 f 146//554 248//469 152//331 f 249//492 146//554 144//344 f 249//492 151//346 145//338 f 136//316 152//331 237//415 f 233//435 213//588 235//529 f 248//469 213//588 233//435 f 209//552 210//551 231//563 f 213//588 201//557 205//591 f 96//340 290//423 173//260 f 290//423 96//340 95//347 f 251//599 198//585 205//591 f 231//563 251//599 205//591 f 252//584 203//532 253//490 f 200//458 250//383 253//490 f 248//469 233//435 152//331 f 261//525 166//524 165//572 f 166//524 262//418 230//296 f 230//296 262//418 263//145 f 176//216 263//145 185//171 f 263//145 177//121 230//296 f 263//145 176//216 177//121 f 156//569 264//544 232//616 f 167//538 264//544 156//569 f 265//602 266//530 267//503 f 175//228 268//448 269//559 f 270//548 267//503 271//276 f 272//424 271//276 267//503 f 272//424 267//503 266//530 f 265//602 273//546 274//601 f 275//542 274//601 273//546 f 268//448 276//484 273//546 f 276//484 277//453 275//542 f 276//484 275//542 273//546 f 276//484 268//448 278//293 f 279//93 280//157 281//150 f 278//293 280//157 282//211 f 283//205 282//211 279//93 f 278//293 268//448 280//157 f 284//278 278//293 282//211 f 282//211 283//205 284//278 f 279//93 282//211 280//157 f 276//484 278//293 277//453 f 277//453 278//293 284//278 f 275//305 277//305 274//305 f 284//305 283//305 279//305 f 279//305 277//305 284//305 f 274//305 277//305 279//305 f 281//305 272//305 266//305 f 279//305 281//305 266//305 f 279//305 266//305 274//305 f 265//602 274//601 266//530 f 273//546 265//602 268//448 f 270//548 269//559 265//602 f 268//448 265//602 269//559 f 271//276 272//424 281//150 f 285//124 281//150 280//157 f 281//150 285//124 271//276 f 280//157 268//448 175//228 f 265//602 267//503 270//548 f 270//548 271//276 159//288 f 271//276 285//124 292//128 f 280//157 292//128 285//124 f 292//128 159//288 271//276 f 292//128 280//157 175//228 f 221//581 223//468 225//515 f 220//437 227//444 224//489 f 287//619 288//596 269//559 f 269//559 270//548 287//619 f 288//596 171//451 269//559 f 289//615 232//616 618//598 f 270//548 159//288 359//497 f 287//619 359//497 291//600 f 619//618 287//619 291//600 f 286//576 288//596 619//618 f 155//501 154//507 289//615 f 620//593 619//618 157//597 f 160//477 290//423 97//368 f 95//347 97//368 290//423 f 157//597 291//600 155//501 f 288//596 287//619 619//618 f 159//288 292//128 172//154 f 292//128 175//228 172//154 f 134//399 293//438 139//392 f 130//400 293//438 134//399 f 202//549 294//475 200//458 f 129//386 128//385 294//475 f 212//511 296//595 215//535 f 196//519 296//595 212//511 f 254//325 217//281 295//345 f 216//440 295//345 217//281 f 252//584 296//595 196//519 f 196//519 197//541 252//584 f 251//599 252//584 197//541 f 197//541 198//585 251//599 f 330//531 329//547 328//614 f 327//606 328//614 329//547 f 296//595 331//510 330//531 f 330//531 328//614 296//595 f 296//595 328//614 215//535 f 253//490 331//510 252//584 f 296//595 252//584 331//510 f 329//547 330//531 297//373 f 298//376 297//373 330//531 f 298//376 331//510 299//382 f 331//510 298//376 330//531 f 331//510 253//490 299//382 f 250//383 299//382 253//490 f 333//470 332//479 328//614 f 215//535 328//614 332//479 f 327//606 333//470 328//614 f 334//456 333//470 327//606 f 301//355 333//470 300//359 f 334//456 300//359 333//470 f 302//356 332//479 301//355 f 333//470 301//355 332//479 f 215//535 332//479 216//440 f 295//345 216//440 302//356 f 216//440 332//479 302//356 f 327//606 329//547 336//555 f 336//555 335//518 327//606 f 329//547 297//373 303//369 f 303//369 336//555 329//547 f 334//456 327//606 335//518 f 300//359 334//456 335//518 f 335//518 304//366 300//359 f 335//518 336//555 338//564 f 338//564 337//516 335//518 f 336//555 303//369 305//362 f 305//362 338//564 336//555 f 304//366 335//518 337//516 f 337//516 306//371 304//366 f 337//516 338//564 340//566 f 340//566 339//517 337//516 f 338//564 305//362 307//357 f 307//357 340//566 338//564 f 306//371 337//516 339//517 f 339//517 308//374 306//371 f 339//517 340//566 342//571 f 342//571 341//520 339//517 f 340//566 307//357 309//354 f 309//354 342//571 340//566 f 308//374 339//517 341//520 f 341//520 310//377 308//374 f 341//520 342//571 344//577 f 344//577 343//514 341//520 f 342//571 309//354 311//349 f 311//349 344//577 342//571 f 310//377 341//520 343//514 f 343//514 312//381 310//377 f 343//514 344//577 346//578 f 346//578 345//513 343//514 f 344//577 311//349 313//339 f 313//339 346//578 344//577 f 312//381 343//514 345//513 f 345//513 314//389 312//381 f 345//513 346//578 348//573 f 348//573 347//509 345//513 f 346//578 313//339 315//327 f 315//327 348//573 346//578 f 314//389 345//513 347//509 f 347//509 316//396 314//389 f 347//509 348//573 350//574 f 350//574 349//506 347//509 f 348//573 315//327 317//308 f 317//308 350//574 348//573 f 316//396 347//509 349//506 f 349//506 318//401 316//396 f 349//506 350//574 352//575 f 352//575 351//498 349//506 f 350//574 317//308 319//323 f 319//323 352//575 350//574 f 318//401 349//506 351//498 f 351//498 320//394 318//401 f 351//498 352//575 354//583 f 354//583 353//496 351//498 f 352//575 319//323 321//329 f 321//329 354//583 352//575 f 320//394 351//498 353//496 f 353//496 322//402 320//394 f 353//496 354//583 356//493 f 356//493 355//412 353//496 f 354//583 321//329 323//352 f 323//352 356//493 354//583 f 322//402 353//496 355//412 f 355//412 324//380 322//402 f 355//412 356//493 358//239 f 358//239 357//274 355//412 f 325//391 358//239 356//493 f 356//493 323//352 325//391 f 324//380 355//412 357//274 f 357//274 326//353 324//380 f 147//360 146//554 152//331 f 172//154 290//423 159//288 f 160//477 291//600 359//497 f 360//156 149//334 148//309 f 150//336 360//156 148//309 f 147//360 360//156 150//336 f 144//344 149//334 360//156 f 457//218 151//346 144//344 f 90//403 362//203 361//263 f 362//203 90//403 91//404 f 93//390 363//209 92//398 f 94//388 363//209 93//390 f 362//203 440//94 364//141 f 361//263 89//405 90//403 f 362//203 91//404 363//209 f 92//398 363//209 91//404 f 368//233 363//209 94//388 f 436//142 373//138 464//166 f 366//182 486//137 379//259 f 362//203 489//95 440//94 f 365//113 489//95 363//209 f 383//482 379//259 469//151 f 491//110 363//209 368//233 f 487//91 528//213 470//162 f 379//259 486//137 488//116 f 368//233 98//351 97//368 f 367//422 528//213 490//287 f 528//213 368//233 490//287 f 380//556 490//287 381//450 f 98//351 369//167 372//271 f 369//167 98//351 368//233 f 100//387 101//384 369//167 f 370//174 102//375 103//370 f 104//367 370//174 103//370 f 368//233 100//387 369//167 f 100//387 368//233 94//388 f 370//174 101//384 102//375 f 370//174 369//167 101//384 f 370//174 104//367 403//105 f 104//367 118//364 403//105 f 403//105 371//227 370//174 f 371//227 372//271 369//167 f 369//167 370//174 371//227 f 371//227 403//105 105//361 f 105//361 106//335 371//227 f 106//335 107//306 372//271 f 372//271 371//227 106//335 f 372//271 107//306 99//341 f 373//138 436//142 374//186 f 396//183 388//120 461//185 f 436//142 437//261 438//414 f 437//261 436//142 621//112 f 366//182 386//289 437//261 f 377//283 108//343 376//224 f 108//343 377//283 109//342 f 377//283 378//443 110//330 f 110//330 109//342 377//283 f 373//138 384//494 377//283 f 386//289 111//318 385//589 f 385//589 112//332 384//494 f 113//322 378//443 112//332 f 256//312 255//310 379//259 f 114//314 379//259 255//310 f 115//320 379//259 114//314 f 113//322 110//330 378//443 f 386//289 116//321 111//318 f 386//289 115//320 116//321 f 386//289 379//259 115//320 f 379//259 257//324 256//312 f 380//556 382//459 383//482 f 380//556 381//450 382//459 f 382//459 379//259 383//482 f 257//324 382//459 117//319 f 382//459 258//307 117//319 f 382//459 259//315 258//307 f 382//459 381//450 259//315 f 259//315 381//450 260//328 f 260//328 381//450 96//340 f 257//324 379//259 382//459 f 391//265 384//494 373//138 f 386//289 385//589 438//414 f 461//185 374//186 462//292 f 385//589 111//318 112//332 f 378//443 384//494 112//332 f 462//292 387//282 461//185 f 437//261 386//289 438//414 f 384//494 378//443 377//283 f 377//283 376//224 375//172 f 99//341 98//351 372//271 f 461//185 387//282 396//183 f 390//170 388//120 402//107 f 402//107 397//168 390//170 f 389//230 391//265 390//170 f 399//257 389//230 397//168 f 397//168 389//230 390//170 f 391//265 389//230 395//419 f 393//539 401//609 392//545 f 393//539 395//419 394//502 f 394//502 400//505 401//609 f 391//265 395//419 393//539 f 395//419 398//432 394//502 f 400//505 394//502 398//432 f 394//502 401//609 393//539 f 395//419 389//230 399//257 f 395//419 399//257 398//432 f 399//305 397//305 402//305 f 400//305 398//305 401//406 f 399//305 401//406 398//305 f 399//305 402//305 401//406 f 387//408 392//410 396//407 f 392//410 401//406 396//407 f 396//407 401//406 402//305 f 402//107 388//120 396//183 f 388//120 390//170 391//265 f 388//120 373//138 461//185 f 388//120 391//265 373//138 f 387//282 462//292 392//545 f 392//545 463//565 393//539 f 463//565 392//545 462//292 f 391//265 393//539 384//494 f 403//105 118//364 121//358 f 105//361 403//105 119//365 f 120//622 121//358 118//364 f 119//365 403//105 121//358 f 123//622 121//358 120//622 f 123//622 122//622 121//358 f 122//622 123//622 124//378 f 125//363 124//378 123//622 f 124//378 125//363 455//99 f 126//348 455//99 125//363 f 455//99 127//372 124//378 f 377//283 375//172 464//166 f 375//172 427//131 364//141 f 414//149 439//147 459//126 f 128//385 494//235 408//252 f 131//397 89//405 361//263 f 361//263 132//395 131//397 f 133//393 427//131 407//264 f 139//392 133//393 407//264 f 408//252 250//383 128//385 f 408//252 411//178 460//220 f 408//252 410//161 411//178 f 412//253 421//122 409//153 f 414//149 411//178 410//161 f 416//103 413//119 415//148 f 418//159 410//161 417//158 f 439//147 414//149 418//159 f 417//158 415//148 439//147 f 422//90 419//143 405//169 f 442//188 419//143 447//106 f 406//125 422//90 405//169 f 406//125 421//122 422//90 f 419//143 404//191 405//169 f 406//125 413//119 421//122 f 422//90 421//122 443//181 f 404//191 419//143 442//188 f 442//188 444//245 404//191 f 444//245 423//175 420//199 f 420//199 404//191 444//245 f 138//317 412//253 409//153 f 412//253 138//317 135//313 f 136//316 254//325 425//429 f 427//131 133//393 132//395 f 427//131 409//153 426//98 f 409//153 427//131 375//172 f 375//172 376//224 409//153 f 138//317 409//153 376//224 f 138//317 376//224 137//333 f 108//343 137//333 376//224 f 427//131 361//263 364//141 f 361//263 427//131 132//395 f 377//283 464//166 373//138 f 428//273 129//386 130//400 f 139//392 407//264 493//272 f 429//129 427//131 430//89 f 426//98 430//89 427//131 f 432//221 428//273 431//242 f 433//195 432//221 431//242 f 493//272 407//264 431//242 f 428//273 493//272 431//242 f 130//400 493//272 428//273 f 433//195 429//129 434//100 f 407//264 429//129 431//242 f 429//129 407//264 427//131 f 433//195 494//235 129//386 f 435//266 432//221 129//386 f 428//273 435//266 129//386 f 410//161 494//235 434//100 f 436//142 440//94 621//112 f 374//186 436//142 438//414 f 414//149 459//126 411//178 f 413//119 439//147 415//148 f 459//126 439//147 458//111 f 410//161 418//159 414//149 f 440//94 436//142 464//166 f 366//182 379//259 386//289 f 136//316 425//429 445//295 f 445//295 441//275 152//331 f 424//270 445//295 425//429 f 424//270 423//175 444//245 f 453//237 445//295 424//270 f 424//270 444//245 453//237 f 429//129 430//89 446//102 f 416//103 446//102 430//89 f 430//89 426//98 416//103 f 446//102 416//103 410//161 f 416//103 426//98 409//153 f 416//103 409//153 413//119 f 410//161 434//100 446//102 f 429//129 446//102 434//100 f 434//100 494//235 433//195 f 432//221 433//195 129//386 f 410//161 416//103 417//158 f 415//148 417//158 416//103 f 447//106 448//243 442//188 f 449//130 447//106 419//143 f 422//90 449//130 419//143 f 450//202 449//130 422//90 f 422//90 443//181 450//202 f 443//181 441//275 450//202 f 451//255 450//202 441//275 f 444//245 442//188 452//232 f 448//243 452//232 442//188 f 454//238 451//255 441//275 f 441//275 445//295 454//238 f 445//295 453//237 454//238 f 453//237 444//245 452//232 f 140//337 455//99 126//348 f 127//372 455//99 141//350 f 455//99 140//337 142//311 f 141//350 455//99 142//311 f 362//203 364//141 361//263 f 621//112 489//95 622//117 f 421//122 412//253 456//241 f 412//253 135//313 143//326 f 456//241 412//253 143//326 f 456//241 143//326 145//338 f 457//218 360//156 456//241 f 456//241 145//338 457//218 f 456//241 360//156 152//331 f 360//156 457//218 144//344 f 151//346 457//218 145//338 f 152//331 136//316 445//295 f 421//122 441//275 443//181 f 421//122 456//241 441//275 f 418//159 417//158 439//147 f 409//153 421//122 413//119 f 490//287 96//340 381//450 f 96//340 490//287 95//347 f 406//125 458//111 413//119 f 458//111 439//147 413//119 f 411//178 459//126 460//220 f 250//383 408//252 460//220 f 441//275 456//241 152//331 f 374//186 461//185 373//138 f 462//292 374//186 438//414 f 462//292 438//414 463//565 f 463//565 384//494 393//539 f 385//589 463//565 438//414 f 384//494 463//565 385//589 f 464//166 364//141 440//94 f 464//166 375//172 364//141 f 466//180 465//108 467//207 f 468//262 383//482 469//151 f 467//207 470//162 471//434 f 471//434 472//286 467//207 f 467//207 472//286 466//180 f 473//164 465//108 474//109 f 474//109 475//168 473//164 f 476//226 468//262 473//164 f 477//257 476//226 475//168 f 475//168 476//226 473//164 f 468//262 476//226 478//417 f 480//553 479//617 481//560 f 480//553 478//417 482//499 f 482//499 483//505 479//617 f 468//262 478//417 480//553 f 478//417 484//432 482//499 f 483//505 482//499 484//432 f 482//499 479//617 480//553 f 478//417 476//226 477//257 f 478//417 477//257 484//432 f 477//305 475//305 474//305 f 483//305 484//305 479//305 f 477//305 479//305 484//305 f 477//305 474//305 479//305 f 472//305 481//305 466//305 f 481//305 479//305 466//305 f 466//305 479//305 474//305 f 474//109 465//108 466//180 f 465//108 473//164 468//262 f 469//151 470//162 465//108 f 465//108 468//262 469//151 f 472//286 471//434 481//560 f 481//560 485//586 480//553 f 485//586 481//560 471//434 f 468//262 480//553 383//482 f 467//207 465//108 470//162 f 471//434 470//162 367//422 f 485//586 471//434 492//582 f 492//582 480//553 485//586 f 367//422 492//582 471//434 f 480//553 492//582 383//482 f 431//242 429//129 433//195 f 435//266 428//273 432//221 f 488//116 487//91 469//151 f 470//162 469//151 487//91 f 379//259 488//116 469//151 f 440//94 489//95 621//112 f 367//422 470//162 528//213 f 528//213 487//91 491//110 f 487//91 623//92 491//110 f 622//117 623//92 486//137 f 362//203 363//209 489//95 f 622//117 489//95 365//113 f 490//287 368//233 97//368 f 97//368 95//347 490//287 f 491//110 365//113 363//209 f 623//92 487//91 488//116 f 492//582 367//422 380//556 f 383//482 492//582 380//556 f 493//272 134//399 139//392 f 493//272 130//400 134//399 f 494//235 410//161 408//252 f 128//385 129//386 494//235 f 495//114 420//199 423//175 f 495//114 404//191 420//199 f 425//429 254//325 295//345 f 295//345 424//270 425//429 f 495//114 459//126 404//191 f 405//169 404//191 459//126 f 459//126 458//111 405//169 f 406//125 405//169 458//111 f 498//163 499//179 497//96 f 497//96 496//104 498//163 f 500//200 495//114 499//179 f 497//96 499//179 495//114 f 497//96 495//114 423//175 f 500//200 460//220 459//126 f 459//126 495//114 500//200 f 499//179 498//163 297//373 f 297//373 298//376 499//179 f 500//200 298//376 299//382 f 298//376 500//200 499//179 f 460//220 500//200 299//382 f 299//382 250//383 460//220 f 501//231 502//240 497//96 f 497//96 423//175 501//231 f 502//240 496//104 497//96 f 502//240 503//254 496//104 f 502//240 301//355 300//359 f 300//359 503//254 502//240 f 501//231 302//356 301//355 f 301//355 502//240 501//231 f 501//231 423//175 424//270 f 424//270 295//345 302//356 f 501//231 424//270 302//356 f 498//163 496//104 505//155 f 504//192 505//155 496//104 f 297//373 498//163 303//369 f 505//155 303//369 498//163 f 496//104 503//254 504//192 f 503//254 300//359 504//192 f 304//366 504//192 300//359 f 505//155 504//192 507//146 f 506//194 507//146 504//192 f 303//369 505//155 305//362 f 507//146 305//362 505//155 f 504//192 304//366 506//194 f 306//371 506//194 304//366 f 507//146 506//194 509//144 f 508//193 509//144 506//194 f 305//362 507//146 307//357 f 509//144 307//357 507//146 f 506//194 306//371 508//193 f 308//374 508//193 306//371 f 509//144 508//193 511//139 f 510//190 511//139 508//193 f 307//357 509//144 309//354 f 511//139 309//354 509//144 f 508//193 308//374 510//190 f 310//377 510//190 308//374 f 511//139 510//190 513//133 f 512//196 513//133 510//190 f 309//354 511//139 311//349 f 513//133 311//349 511//139 f 510//190 310//377 512//196 f 312//381 512//196 310//377 f 513//133 512//196 515//132 f 514//197 515//132 512//196 f 311//349 513//133 313//339 f 515//132 313//339 513//133 f 512//196 312//381 514//197 f 314//389 514//197 312//381 f 515//132 514//197 517//136 f 516//201 517//136 514//197 f 313//339 515//132 315//327 f 517//136 315//327 515//132 f 514//197 314//389 516//201 f 316//396 516//201 314//389 f 517//136 516//201 519//135 f 518//204 519//135 516//201 f 315//327 517//136 317//308 f 519//135 317//308 517//136 f 516//201 316//396 518//204 f 318//401 518//204 316//396 f 519//135 518//204 521//134 f 520//212 521//134 518//204 f 317//308 519//135 319//323 f 521//134 319//323 519//135 f 518//204 318//401 520//212 f 320//394 520//212 318//401 f 521//134 520//212 523//127 f 522//214 523//127 520//212 f 319//323 521//134 321//329 f 523//127 321//329 521//134 f 520//212 320//394 522//214 f 322//402 522//214 320//394 f 523//127 522//214 525//217 f 524//298 525//217 522//214 f 321//329 523//127 323//352 f 525//217 323//352 523//127 f 522//214 322//402 524//298 f 324//380 524//298 322//402 f 525//217 524//298 527//471 f 526//436 527//471 524//298 f 527//471 325//391 525//217 f 323//352 525//217 325//391 f 524//298 324//380 526//436 f 326//353 526//436 324//380 f 360//156 147//360 152//331 f 490//287 380//556 367//422 f 491//110 368//233 528//213 f 533//431 534//420 531//433 f 532//416 531//433 534//420 f 549//442 533//431 531//433 f 540//558 539//592 538//526 f 541//587 560//570 559//613 f 560//570 541//587 539//592 f 538//526 539//592 541//587 f 561//491 541//587 559//613 f 535//413 536//460 542//485 f 536//460 545//500 542//485 f 545//500 536//460 538//526 f 546//487 545//500 541//587 f 538//526 541//587 545//500 f 561//491 546//487 541//587 f 547//426 545//500 546//487 f 546//487 562//441 547//426 f 563//299 547//426 562//441 f 564//285 547//426 563//299 f 545//500 548//452 544//512 f 548//452 543//495 558//504 f 543//495 548//452 530//481 f 544//512 548//452 558//504 f 545//500 547//426 548//452 f 565//280 547//426 564//285 f 565//280 566//301 547//426 f 548//452 547//426 566//301 f 549//442 548//452 566//301 f 549//442 531//433 548//452 f 548//452 531//433 530//481 f 537//474 529//454 550//463 f 538//526 552//521 540//558 f 568//476 554//464 567//461 f 568//476 555//488 554//464 f 553//466 554//464 555//488 f 555//488 568//476 569//533 f 537//474 556//523 536//460 f 550//463 555//488 537//474 f 553//466 555//488 551//462 f 550//463 551//462 555//488 f 555//488 569//533 570//537 f 537//474 555//488 556//523 f 571//550 556//523 570//537 f 556//523 555//488 570//537 f 538//526 557//534 552//521 f 556//523 557//534 538//526 f 536//460 556//523 538//526 f 572//594 557//534 556//523 f 571//550 572//594 556//523 f 544//512 542//485 545//500 f 558//504 542//485 544//512 f 562//441 546//487 561//491 f 578//290 577//279 575//277 f 575//277 576//294 578//290 f 577//279 593//268 575//277 f 583//118 584//152 582//184 f 604//140 585//123 603//97 f 585//123 604//140 583//118 f 583//118 582//184 585//123 f 585//123 605//219 603//97 f 580//250 579//297 586//225 f 589//210 580//250 586//225 f 580//250 589//210 582//184 f 589//210 590//223 585//123 f 585//123 582//184 589//210 f 590//223 605//219 585//123 f 589//210 591//284 590//223 f 606//269 590//223 591//284 f 591//284 607//411 606//269 f 591//284 608//425 607//411 f 592//258 589//210 588//198 f 587//215 592//258 602//206 f 592//258 587//215 574//229 f 592//258 588//198 602//206 f 591//284 589//210 592//258 f 591//284 609//430 608//425 f 610//409 609//430 591//284 f 591//284 592//258 610//409 f 592//258 593//268 610//409 f 575//277 593//268 592//258 f 575//277 592//258 574//229 f 573//256 581//236 594//247 f 596//189 582//184 584//152 f 598//246 612//234 611//249 f 599//222 612//234 598//246 f 598//246 597//244 599//222 f 612//234 599//222 613//177 f 600//187 581//236 580//250 f 599//222 594//247 581//236 f 599//222 597//244 595//248 f 595//248 594//247 599//222 f 613//177 599//222 614//173 f 599//222 581//236 600//187 f 600//187 615//160 614//173 f 599//222 600//187 614//173 f 601//176 582//184 596//189 f 601//176 600//187 582//184 f 600//187 580//250 582//184 f 601//176 616//115 600//187 f 616//115 615//160 600//187 f 586//225 588//198 589//210 f 586//225 602//206 588//198 f 590//223 606//269 605//219 f 357//274 358//239 617//379 f 358//239 325//391 617//379 f 326//353 357//274 617//379 f 527//471 526//436 617//379 f 325//391 527//471 617//379 f 526//436 326//353 617//379 f 158//528 618//598 229//449 f 618//598 158//528 620//593 f 157//597 619//618 291//600 f 620//593 157//597 289//615 f 620//593 158//528 286//576 f 619//618 620//593 286//576 f 621//112 366//182 437//261 f 366//182 621//112 622//117 f 366//182 622//117 486//137 f 488//116 486//137 623//92 f 491//110 623//92 365//113 f 623//92 622//117 365//113 tests/meshes/ply/000077500000000000000000000000001456244072500143215ustar00rootroot00000000000000tests/meshes/ply/bun_zipper_res4.ply000066400000000000000000001030671456244072500201700ustar00rootroot00000000000000ply format ascii 1.0 comment zipper output element vertex 453 property float x property float y property float z property float confidence property float intensity element face 948 property list uchar int vertex_indices end_header -0.0312216 0.126304 0.00514924 0.850855 0.5 -0.0446774 0.131204 0.00570479 0.900159 0.5 -0.0683011 0.144828 0.0413688 0.398443 0.5 -0.00600095 0.130398 0.0178986 0.85268 0.5 -0.0173568 0.127613 0.00526885 0.675938 0.5 0.0330513 0.107034 0.0319543 0.652757 0.5 0.0400873 0.10521 0.0173419 0.708171 0.5 -0.0301802 0.106322 0.0399745 0.454541 0.437538 0.0304193 0.118572 0.0188068 0.533079 0.5 -0.0640822 0.159391 -0.0169096 0.404517 0.5 0.0447046 0.0927877 0.00507585 0.579563 0.425995 -0.0316754 0.170395 -0.00635023 0.365607 0.5 -0.0848523 0.134078 0.0470177 0.499575 0.5 -0.0688547 0.122052 0.0517569 0.564827 0.5 0.00595475 0.131024 0.0178252 0.748371 0.5 0.0404629 0.105142 0.00640978 0.680399 0.5 0.0387342 0.102161 -0.00463112 0.600054 0.5 -0.0914513 0.134136 0.0171026 0.824561 0.5 -0.0818721 0.107166 0.031016 0.690889 0.5 -0.067218 0.156155 0.0178863 0.807492 0.5 -0.0795687 0.152875 0.0299311 0.248168 0.41865 0.00596007 0.122504 0.0346272 0.555044 0.354559 -0.0516317 0.145001 0.0184804 0.691477 0.5 -0.0779781 0.13255 0.0513494 0.566256 0.5 -0.00590708 0.127934 0.0274623 0.271491 0.462815 -0.0479133 0.129301 0.0269646 0.539149 0.5 -0.082427 0.0928134 -0.00556046 0.710999 0.5 0.01744 0.127694 0.0185348 0.530957 0.5 -0.0906868 0.120305 0.0066804 0.635593 0.5 -0.0294038 0.17903 -0.00787959 0.269231 0.447035 -0.0797891 0.14376 0.0426994 0.414139 0.5 -0.018288 0.108329 0.0415098 0.482541 0.5 -0.0202326 0.181846 -0.0183274 0.341071 0.440034 -0.0377039 0.167987 -0.0130391 0.396317 0.473039 0.00582164 0.12806 0.0279016 0.350014 0.41288 -0.0435389 0.130014 0.0175333 0.599596 0.5 0.0188699 0.119862 0.032409 0.625269 0.5 -0.0440101 0.167035 0.00231898 0.413994 0.469929 -0.089811 0.132401 0.00705743 0.625486 0.5 -0.057352 0.144989 0.0315196 0.696873 0.5 0.0442622 0.0934526 0.0176417 0.665192 0.5 0.0412343 0.0921731 0.0285603 0.671611 0.5 -0.0563953 0.154565 0.016878 0.394763 0.437313 -0.0206135 0.159773 -0.00717522 0.136389 0.380194 -0.0729893 0.0656116 0.0181693 0.413051 0.5 -0.0673967 0.155256 0.00581389 0.855717 0.5 -0.0904864 0.118611 0.0412148 0.673877 0.5 0.0273142 0.117965 0.0286191 0.635485 0.5 0.041907 0.0916386 -0.00556945 0.585857 0.459742 -0.0702109 0.165303 -0.0194661 0.548789 0.5 -0.0061847 0.122729 0.034787 0.602316 0.374044 0.0300138 0.0932786 0.0421476 0.649753 0.5 -0.0175129 0.162126 -0.0145489 0.338176 0.5 -0.0763977 0.171291 -0.0411021 0.256591 0.4298 -0.0854227 0.105386 0.00339486 0.523819 0.297125 0.0370431 0.110443 0.0207229 0.52623 0.448558 -0.00659732 0.0427285 0.0469391 0.280725 0.5 0.00639794 0.0437006 0.046826 0.331809 0.5 -0.0559247 0.157606 0.00656455 0.561042 0.5 -0.0911449 0.118816 0.0298442 0.848517 0.5 -0.0595109 0.128352 0.0399626 0.658867 0.444043 -0.0176335 0.127605 0.0179366 0.547632 0.5 -0.066633 0.153831 0.0308703 0.855321 0.5 -0.0436418 0.169438 -0.00550226 0.274377 0.177706 -0.0572759 0.043243 0.042862 0.417977 0.459314 -0.0763773 0.157221 -0.0168889 0.267801 0.372187 -0.0434461 0.15605 0.00615795 0.447592 0.5 -0.0427118 0.0421645 0.0427004 0.509262 0.5 -0.0254201 0.0886622 0.0503827 0.608282 0.5 -0.014179 0.12627 0.0266417 0.420759 0.5 -0.0882582 0.0898687 0.00696625 0.753697 0.5 -0.0688695 0.157773 -0.00687593 0.595216 0.5 -0.0679676 0.142877 -0.00757643 0.446131 0.5 0.0188538 0.106293 0.0416902 0.669811 0.5 -0.036487 0.171225 0.000545037 0.438578 0.5 -0.0664352 0.117198 -0.00987161 0.569796 0.5 -0.0682606 0.170398 -0.0436995 0.381568 0.451091 -0.090925 0.14605 0.0190382 0.648478 0.5 0.00678622 0.115841 0.0388077 0.549283 0.408623 0.0310139 0.0930696 -0.017798 0.732658 0.5 0.0056976 0.10589 0.0435511 0.592572 0.5 -0.0706519 0.13063 0.0502497 0.563116 0.5 0.0059746 0.130858 0.00579479 0.795238 0.5 0.0184217 0.0423182 0.042477 0.259499 0.426724 0.0147876 0.0909747 0.0509658 0.654705 0.5 -0.00598232 0.115409 0.0402027 0.615633 0.5 -0.0811312 0.117972 -0.00359453 0.505277 0.5 -0.0787032 0.144274 -0.00389052 0.466714 0.5 0.00581988 0.106226 -0.0208968 0.792948 0.5 -0.0192761 0.119853 0.0328061 0.445477 0.415699 -0.00593116 0.130215 0.005954 0.738924 0.5 -0.0893322 0.142745 0.0290326 0.80362 0.5 -0.00762538 0.123273 -0.00981555 0.767738 0.284429 -0.0692263 0.178922 -0.0542743 0.245129 0.411885 -0.0298757 0.124252 0.0209674 0.32811 0.5 -0.0848266 0.148987 0.0327697 0.331963 0.314683 -0.0888516 0.0909723 0.0179034 0.603378 0.5 -0.0305879 0.122384 -0.00635771 0.63839 0.5 -0.0307198 0.117989 0.0306166 0.543293 0.5 -0.0780612 0.120653 0.0513999 0.490413 0.5 0.0332714 0.108498 -0.00743195 0.534403 0.5 -0.0677112 0.0928918 -0.0168814 0.511499 0.5 -0.075666 0.0911817 -0.0136967 0.429902 0.5 -0.082422 0.0951121 0.0310878 0.678588 0.5 -0.0856984 0.136903 0.00192122 0.517441 0.5 -0.0292804 0.0417747 0.051397 0.553401 0.5 -0.017732 0.0423864 0.051684 0.709553 0.5 -0.0656987 0.171007 -0.056644 0.549906 0.5 -0.0298523 0.170905 -0.0165609 0.436075 0.5 -0.0562502 0.135013 0.0330455 0.727547 0.5 -0.0666127 0.133021 0.0447044 0.724494 0.5 -0.0425379 0.155441 -0.00749353 0.424682 0.5 -0.0545308 0.0714603 0.0397042 0.682177 0.456916 -0.0413159 0.0906923 -0.0225881 0.72469 0.5 -0.0172876 0.0921774 0.0536212 0.546444 0.5 -0.00598119 0.0940308 0.0542643 0.455087 0.5 0.0423724 0.0672563 0.0295801 0.33948 0.5 0.0285741 0.116909 -0.00391772 0.66246 0.5 -0.0331811 0.0450744 0.0451146 0.432059 0.466683 -0.0539402 0.118566 0.0353731 0.515399 0.5 0.0422724 0.0795546 -0.00579461 0.568535 0.5 0.0297273 0.0425502 0.0304975 0.650152 0.5 -0.0315639 0.0959331 -0.0236801 0.474586 0.431409 0.0381804 0.105121 0.0266947 0.534482 0.490368 -0.0284988 0.090492 -0.0290854 0.294426 0.332222 -0.0173189 0.0437942 0.0432695 0.576068 0.5 0.00376754 0.0477551 0.0502037 0.495901 0.44823 0.0432673 0.0458291 0.0278251 0.807573 0.5 -0.0233322 0.181239 -0.0112893 0.246322 0.458572 -0.0056258 0.0565038 0.0538818 0.61481 0.5 0.00529431 0.0556798 0.0532881 0.560812 0.423049 -0.0883219 0.105757 0.0172983 0.604102 0.5 -0.0566374 0.0470184 0.0305809 0 0 -0.0296243 0.0543188 0.0398951 0.676102 0.5 -0.00597407 0.105897 0.0440669 0.338462 0.5 -0.0214122 0.0546976 0.044641 0.195646 0.404388 -0.0161488 0.0574363 0.050904 0.451613 0.5 -0.0568305 0.146392 -0.0026426 0.48145 0.5 -0.0931466 0.119067 0.0179948 0.570519 0.5 -0.061862 0.158417 -0.0293026 0.690546 0.5 -0.0855858 0.10684 0.021729 0.519516 0.5 0.0336642 0.0540543 0.0350841 0.609925 0.5 0.042771 0.0560351 0.031559 0.669803 0.5 -0.0434589 0.117191 0.0317044 0.657986 0.5 -0.0680962 0.156721 -0.0426174 0.523327 0.5 0.0272384 0.103156 0.0397058 0.689793 0.5 -0.0293932 0.178536 -0.0145563 0.314049 0.5 -0.0762697 0.0912245 0.0383419 0.647987 0.457049 -0.0191285 0.0985952 0.0456676 0.271215 0.427554 -0.053091 0.0567402 0.0293963 0.192432 0.5 -0.0431978 0.0555777 0.0390838 0.311543 0.5 -0.0833055 0.115643 0.046828 0.438131 0.5 0.0144345 0.127081 0.026297 0.479299 0.429147 -0.0388913 0.123761 0.0249778 0.514489 0.5 -0.0594359 0.119905 0.0399756 0.634635 0.5 -0.0702332 0.154262 -0.0312401 0.685413 0.5 -0.0574473 0.152576 0.0284508 0.93076 0.5 -0.0480038 0.056366 0.0362663 0.58186 0.5 -0.0107262 0.179662 -0.0277472 0.400699 0.458536 -0.0882293 0.106066 0.00846756 0.477822 0.5 -0.078994 0.153984 0.00651862 0.57436 0.5 -0.0295675 0.126072 0.0146338 0.393422 0.5 -0.0817356 0.15439 0.0177332 0.505065 0.5 -0.0795469 0.104194 -0.00620274 0.528684 0.5 -0.0248608 0.122913 0.0245429 0.379391 0.5 -0.0664416 0.159957 -0.0533713 0.38665 0.5 -0.0784878 0.0705283 0.0174461 0.703257 0.5 -0.00967101 0.173225 -0.0264945 0.379771 0.5 -0.0566284 0.0547031 0.00744563 0.270787 0.5 -0.0184015 0.122219 -0.00775134 0.782181 0.5 -0.0695952 0.146412 -0.018032 0.130446 0.5 -0.0412517 0.123196 -0.00958087 0.590842 0.5 -0.0684972 0.148194 -0.028726 0.690046 0.5 -0.0540036 0.055543 0.0177674 0.079935 0 -0.0169203 0.0682168 0.0531499 0.608033 0.445048 -0.00607221 0.0677102 0.0564501 0.650491 0.470895 0.00708728 0.0673218 0.0553369 0.748671 0.5 -0.0143174 0.116971 0.037836 0.441459 0.5 0.0538923 0.0557547 0.0266244 0.405493 0.41666 0.00517855 0.0931738 0.0535873 0.395048 0.366076 -0.0431038 0.0674388 0.0407737 0.587502 0.5 -0.0293069 0.0680733 0.041016 0.650585 0.5 -0.0379555 0.161954 -0.0128021 0.499753 0.5 -0.0561165 0.0654329 0.0341979 0.277414 0.5 -0.0761707 0.155559 -0.0059272 0.708579 0.5 -0.0552181 0.122506 -0.00946488 0.538005 0.5 0.0177004 0.105983 -0.0186138 0.576137 0.468722 0.0534583 0.0656375 0.0264336 0.501229 0.5 -0.0869152 0.0944156 0.00293118 0.494536 0.346642 -0.0764257 0.161707 -0.0297517 0.476378 0.5 -0.0440959 0.127453 -0.00327875 0.853498 0.5 -0.0312919 0.0798298 0.0434944 0.693464 0.5 -0.0549448 0.106348 -0.0185625 0.484023 0.5 -0.0723735 0.110057 -0.00943257 0.44421 0.5 -0.0553659 0.0919829 -0.0211783 0.619673 0.5 -0.0488091 0.0660127 0.0373959 0.829801 0.5 -0.0473086 0.145156 0.00688469 0.636632 0.45621 -0.0803913 0.129634 -0.00469755 0.386393 0.5 -0.041802 0.105934 -0.0198692 0.79815 0.5 -0.00632139 0.0931652 -0.0328935 0.564234 0.5 -0.00597054 0.106138 -0.0222282 0.740261 0.5 -0.0294827 0.158293 -0.00619266 0.209483 0.5 -0.0177953 0.106289 -0.0217771 0.723165 0.5 -0.0885261 0.137839 0.0393964 0.651389 0.5 -0.0674935 0.128392 -0.00863471 0.737784 0.5 0.0463693 0.0715128 0.0216754 0.461473 0.448797 -0.0409565 0.117168 -0.0145809 0.602235 0.5 -0.0106656 0.167541 -0.0199013 0.359593 0.5 -0.0532547 0.157456 -0.00281896 0.292939 0.5 0.00530988 0.0933129 -0.0301852 0.75972 0.5 -0.0773436 0.0727226 0.0266546 0.757943 0.5 -0.0625087 0.149934 -0.0150319 0.415531 0.480025 -0.0688014 0.0685726 0.0306649 0.49936 0.45677 -0.0545252 0.0808478 -0.0201707 0.75515 0.5 -0.0436768 0.078916 0.0428855 0.696934 0.5 -0.0185748 0.0789703 0.0557353 0.607912 0.5 -0.00599993 0.0794548 0.0578008 0.791265 0.5 0.00706485 0.0811917 0.0558187 0.523043 0.5 -0.0850269 0.146034 0.00585954 0.583528 0.5 0.0370111 0.110397 0.00265294 0.516602 0.481774 -0.0683084 0.0803316 0.0407109 0.610448 0.476331 -0.055894 0.0792594 0.0435335 0.634349 0.5 0.0381456 0.0881056 -0.0138675 0.676152 0.5 -0.0642837 0.0396418 0.039624 0.532543 0.5 -0.0698696 0.168536 -0.0313319 0.458525 0.324439 -0.061796 0.155741 -0.0207923 0.443336 0.5 -0.0622848 0.16236 -0.0396288 0.427869 0.464762 -0.0686864 0.0923704 0.0421978 0.59211 0.5 -0.049353 0.139298 0.0147955 0.761861 0.5 -0.0784177 0.110126 0.0417886 0.498936 0.5 0.0179416 0.0792747 0.0518862 0.491924 0.475524 0.00532732 0.123661 -0.00997105 0.555015 0.5 -0.0556774 0.0935206 0.044207 0.778337 0.5 -0.0431924 0.0921154 0.0432689 0.605881 0.5 -0.0298626 0.0940124 0.0444805 0.668172 0.5 0.0205955 0.087113 0.0492325 0.678548 0.5 0.01721 0.127663 0.00512593 0.595962 0.5 -0.0290125 0.106719 -0.0207479 0.809584 0.5 0.0185443 0.0948112 0.0477587 0.669841 0.5 -0.00588676 0.116622 -0.0160049 0.826286 0.5 -0.0528191 0.162649 0.00296711 0.343566 0.5 0.0358078 0.0958594 -0.0120328 0.738943 0.5 -0.0912064 0.131415 0.0295307 0.816274 0.5 -0.067874 0.106952 0.0403725 0.481571 0.5 -0.0441636 0.104918 0.0401706 0.648927 0.395789 0.00749586 0.09835 0.0488255 0.46146 0.5 -0.0554961 0.103898 0.0411405 0.529374 0.5 -0.0669044 0.115717 0.0473479 0.429195 0.5 -0.0501524 0.140326 0.00258818 0.569746 0.5 -0.0554508 0.13242 -0.00485445 0.673026 0.5 -0.014752 0.181897 -0.0262781 0.40888 0.5 -0.029558 0.161783 -0.0143368 0.852313 0.5 -0.0561854 0.111277 0.0373713 0.588374 0.5 -0.040984 0.110496 0.0370883 0.553647 0.5 -0.0320055 0.110468 0.0370438 0.565129 0.5 0.0250033 0.110611 0.0368459 0.631257 0.5 -0.046987 0.147434 -0.00222536 0.521986 0.5 -0.0183407 0.0352362 0.0507938 0.291685 0.457265 -0.0178406 0.170484 -0.0181143 0.809186 0.5 -0.0569472 0.0349416 0.0423717 0.341981 0.5 0.00583339 0.0351076 0.0420914 0.261253 0.345588 -0.0428024 0.0351574 0.0416872 0.193197 0.5 -0.066462 0.104777 -0.0148582 0.608847 0.5 0.0257452 0.0459137 0.0381185 0.444171 0.5 0.0379451 0.0817167 -0.0141547 0.644934 0.5 -0.0844262 0.0797714 0.0186332 0.67606 0.5 0.0532504 0.04759 0.0181903 0.342211 0.398387 0.0186424 0.0536035 0.046215 0.589102 0.5 0.00732515 0.118243 -0.0153012 0.54369 0.457314 -0.0314704 0.157066 0.000976216 0.445666 0.44081 0.0286229 0.056876 0.0407635 0.635463 0.446542 0.0581591 0.0550016 0.0180254 0.474964 0.5 0.016864 0.089935 -0.0269104 0.546403 0.5 0.0145778 0.0585769 0.0501691 0.387785 0.5 0.0367248 0.0918184 0.0366248 0.726421 0.5 -0.0198801 0.166404 -0.0112699 0.688671 0.5 0.0150294 0.0677357 0.0520671 0.554385 0.463079 0.0210524 0.0681161 0.0484346 0.414803 0.412252 0.0298776 0.0679936 0.0419172 0.611901 0.5 0.0368358 0.0678495 0.036641 0.593561 0.5 0.0574748 0.0682218 0.0171425 0.550839 0.448044 0.0316842 0.0785087 -0.019208 0.760295 0.5 -0.0760271 0.175704 -0.0506937 0.340571 0.5 -0.0655396 0.0607885 0.0175707 0.414933 0.425841 -0.0806026 0.081447 0.0306516 0.756683 0.5 0.0189749 0.121506 -0.00694565 0.549 0.5 0.030684 0.0795461 0.0431507 0.572664 0.5 0.0371888 0.0792484 0.0367937 0.505468 0.5 0.0419366 0.0795911 0.0295911 0.645662 0.5 0.046032 0.0793694 0.0177694 0.458504 0.467907 -0.0787921 0.0707773 0.00685585 0.704234 0.277826 -0.0293987 0.115917 -0.0147065 0.856895 0.5 -0.0869924 0.113518 0.00410409 0.344807 0.5 -0.0142186 0.174013 -0.0259807 0.439072 0.5 0.0174795 0.0352131 -0.00592856 0 0 0.0162141 0.0358475 -0.0162131 0.173751 0.5 0.0193248 0.0358322 0.0313206 0.156956 0.287305 0.0435544 0.0411101 0.00579916 0.245023 0.5 0.0226191 0.0406052 -0.00793544 0.173629 0.5 0.0191348 0.042782 -0.0192095 0.367832 0.5 0.0414633 0.0456301 -0.00354513 0.514406 0.5 0.0436925 0.0411968 0.01772 0.265572 0.5 0.0512872 0.0463959 0.00580531 0.199267 0.5 0.0285777 0.105181 -0.0142381 0.728425 0.5 0.0306748 0.0445124 -0.00617993 0.464947 0.5 -0.0184118 0.0948059 -0.0307434 0.520871 0.5 -0.0315484 0.0343023 -0.0284081 0.16856 0.5 0.0260381 0.0475902 -0.0165794 0.515417 0.5 0.0554197 0.0686378 0.00589653 0.629664 0.372945 0.0520374 0.055073 -0.0024816 0.592036 0.5 0.0567375 0.0542224 0.00512483 0.511629 0.5 0.0428049 0.0553286 -0.00604704 0.434179 0.5 -0.0620037 0.167422 -0.0527165 0.538383 0.466596 0.0341128 0.0541776 -0.00948346 0.591066 0.5 0.029518 0.0560564 -0.0175875 0.574224 0.5 -0.0177887 0.115911 -0.0157838 0.559736 0.5 -0.0417838 0.0357602 -0.0264107 0.0979878 0.5 -0.00518939 0.043046 -0.0273333 0.274297 0.5 -0.0664059 0.0343649 -0.00416668 0.135623 0.5 0.0475414 0.0712174 0.00542617 0.590477 0.5 0.0249138 0.0825163 -0.0245877 0.759593 0.5 -0.0299024 0.0426031 -0.0283179 0.537642 0.5 0.0218121 0.0515865 -0.0236492 0.56032 0.5 -0.0271537 0.0351608 0.0509267 0.96808 0.5 0.0161181 0.11563 -0.0145451 0.45799 0.403894 0.031738 0.0679983 -0.0183532 0.581486 0.5 0.0418226 0.0675201 -0.00551555 0.572144 0.5 0.0514871 0.0637279 -0.00174794 0.518067 0.5 -0.0893303 0.128309 0.0428023 0.633972 0.457764 0.0459385 0.0796307 0.00579632 0.323813 0.5 -0.0705433 0.149897 -0.0387319 0.143598 0.5 -0.0429617 0.0430242 -0.0176288 0.371561 0.5 -0.0719677 0.177848 -0.0474604 0.498199 0.393806 -0.0760529 0.177651 -0.0471457 0.200482 0.341482 0.0304173 0.118495 0.00573814 0.517745 0.5 -0.0771451 0.167706 -0.0298798 0.259817 0.452429 0.0202668 0.092861 -0.0237363 0.630702 0.48336 -0.0254815 0.0798697 0.0510546 0.764034 0.5 -0.0650541 0.0353259 0.0162237 0.352362 0.5 -0.0647676 0.0350792 0.0294481 0.161121 0.384305 -0.0644267 0.0414591 0.0304476 0.206373 0.5 -0.06432 0.0352261 0.0387914 0.349097 0.5 -0.0676 0.0340299 0.00590491 0.228898 0.5 -0.0679534 0.0418588 0.00668394 0.30841 0.5 -0.0573497 0.0431548 0.0200229 0 0 -0.0634632 0.0414321 0.0142052 0.258252 0.450399 -0.059413 0.0471382 0.00628538 0.460736 0.319245 -0.0233834 0.0656416 0.0450976 0.709715 0.5 -0.063538 0.071665 0.0379463 0.556494 0.5 -0.0193036 0.0810128 -0.0384318 0.500126 0.449734 -0.0427206 0.0343557 -0.0191302 0.176398 0.205782 -0.00690237 0.03464 -0.0202171 0.15305 0.5 -0.0656787 0.0408332 -0.00401793 0.169982 0.409113 -0.0383907 0.0419218 -0.0264039 0.3765 0.5 -0.0556585 0.0432866 -0.00758834 0.62257 0.5 -0.0416785 0.0420276 -0.00999679 0.340556 0.5 -0.0322294 0.0446593 -0.0167499 0.299501 0.5 -0.0307385 0.0563307 -0.018517 0.265727 0.5 -0.0429026 0.0561897 -0.0113043 0.555432 0.5 -0.0550285 0.0566557 -0.00531375 0.527245 0.5 -0.0261858 0.0568836 -0.0282694 0.366688 0.5 -0.0552189 0.117461 -0.0133744 0.568329 0.5 -0.0190658 0.0546695 -0.0318646 0.484351 0.5 -0.0687629 0.0686694 -0.00654941 0.168435 0.5 -0.0730504 0.06542 0.00552859 0.275779 0.5 -0.0207234 0.0672793 -0.036553 0.45692 0.5 -0.0290792 0.067426 -0.0290521 0.452259 0.5 -0.0328056 0.0664637 -0.0195215 0.908229 0.5 -0.0177608 0.0343319 -0.0259142 0.174612 0.215481 -0.0773687 0.0732571 -0.00409771 0.293636 0.296358 0.0151616 0.126104 -0.00266395 0.542796 0.5 -0.0845255 0.0800572 0.00530702 0.615888 0.5 -0.0793517 0.0798559 -0.00640565 0.260107 0.5 -0.0309728 0.0794701 -0.0312475 0.64535 0.304239 -0.0355144 0.081801 -0.0226887 0.930953 0.5 -0.068141 0.0801227 -0.0164278 0.485274 0.5 -0.0512932 0.034227 -0.0129013 0.159841 0.5 0.0161924 0.080479 -0.0292174 0.750174 0.5 -0.0144478 0.0879274 -0.0380297 0.689122 0.5 -0.0173157 0.0432674 -0.0282906 0.230538 0.5 -0.0193328 0.0979251 -0.024792 0.661276 0.5 -0.0555479 0.0336816 -0.00619013 0.1361 0.5 0.00702627 0.0978418 -0.0246055 0.732067 0.326346 -0.0148892 0.126068 -0.00252126 0.467449 0.5 0.0175205 0.0552114 -0.0272756 0.685576 0.5 -0.00953661 0.0794104 -0.0379859 0.670336 0.467319 0.00524266 0.0391336 -0.021947 0.540697 0.5 0.0175653 0.0679339 -0.0289388 0.690366 0.5 -0.0057907 0.128077 -0.00285105 0.714685 0.5 0.00626556 0.128047 -0.0031705 0.574275 0.5 0.00559979 0.0346604 -0.0179318 0.278473 0.5 0.029824 0.0359142 0.00488977 0.290019 0.5 0.00625193 0.0459623 -0.0263782 0.665265 0.460024 0.0143253 0.0473484 -0.0251513 0.546545 0.456757 0.00604086 0.0555073 -0.0304314 0.840924 0.5 -0.00613413 0.0546372 -0.032635 0.634884 0.475184 -0.0346694 0.057124 -0.0114953 0.102172 0.5 -0.00684543 0.0679742 -0.0359406 0.670518 0.457134 0.0056558 0.0676237 -0.0329199 0.79033 0.385997 -0.0569732 0.0651628 -0.00958219 0.452904 0.5 -0.0422796 0.0699944 -0.0161463 0.543504 0.5 -0.0175719 0.0705473 -0.0382261 0.581028 0.470136 -0.055586 0.0722983 -0.0161218 0.401473 0.5 -0.0637884 0.0712697 -0.0138535 0.437166 0.5 0.00568561 0.0790547 -0.0339189 0.719764 0.5 -0.00338429 0.0804511 -0.0367226 0.799862 0.5 -0.0248988 0.0815004 -0.0371078 0.39297 0.457854 -0.0412513 0.0791378 -0.0197746 0.273711 0.5 -0.0735819 0.0777026 -0.0122023 0.445372 0.5 -0.018062 0.0352627 -0.0195401 0.319674 0.5 -0.031577 0.0358487 -0.0179669 0.482378 0.5 -0.00602034 0.0381237 -0.0145184 0.909294 0.5 -0.0177811 0.0382546 -0.0154503 0.887215 0.5 0.00753447 0.0355596 -0.00650063 0.962688 0.5 0.00430437 0.0384017 -0.0071754 0.927286 0.5 -0.00593935 0.038948 -0.00592129 0.816802 0.5 -0.0176142 0.0386055 -0.00584508 0.759701 0.5 -0.0430308 0.0341391 -0.00565972 0.772585 0.5 0.0189222 0.0351076 0.00499769 0.579133 0.5 -0.0299129 0.0383912 -0.00582677 0.752109 0.5 0.00512066 0.0348398 0.00558498 0.588251 0.5 0.00103528 0.0375917 0.000952222 0.441385 0.5 -0.00584714 0.0383419 0.00590803 0.728422 0.5 -0.0424621 0.0343144 0.00590597 0.266658 0.5 -0.017873 0.0383166 0.00599471 0.753895 0.5 0.028662 0.0358411 0.0187496 0.360666 0.5 -0.055026 0.0336204 0.00583816 0.742717 0.5 -0.0284733 0.0381489 0.00441853 0.456211 0.5 -0.000947006 0.0357374 0.0103469 0.779853 0.5 0.0193224 0.0351814 0.0196616 0.180494 0.5 -0.0342325 0.033759 0.00717517 0.152905 0 0.00536022 0.0345956 0.0179871 0.676527 0.5 -0.000385714 0.0351459 0.0134171 0.848157 0.5 0.0334119 0.0376179 0.0210082 0.70177 0.5 -0.00589791 0.0381782 0.0177062 0.797449 0.5 -0.0352445 0.0350571 0.0178257 0.572312 0.5 -0.0178078 0.0381962 0.0178114 0.753708 0.5 -0.0261898 0.0377592 0.0177044 0.146481 0.5 -0.0563247 0.0336762 0.0175265 0.458851 0.5 0.00114114 0.037661 0.0223414 0.978558 0.5 0.0100253 0.0355029 0.029656 0.701449 0.5 0.00550127 0.0385556 0.0296609 0.996029 0.5 -0.00596581 0.0388946 0.0299252 0.805634 0.5 -0.0330745 0.0355217 0.0292236 0.263742 0.5 -0.0277717 0.0382563 0.0322865 0.074682 0.5 -0.0179091 0.0385902 0.0296167 0.782021 0.5 -0.0419404 0.0343698 0.0299668 0.109729 0 0.015243 0.0356116 0.0412692 0.759188 0.5 -0.0554301 0.0342555 0.0297952 0.808252 0.5 -0.0660515 0.0611144 0.00585548 0.442355 0.5 -0.00654912 0.0350372 0.0453959 0.139343 0 -0.0307826 0.0347596 0.0432959 0.154826 0.5 -0.0180834 0.0348142 0.0458772 0.143796 0.5 3 164 94 98 3 224 335 49 3 331 350 376 3 124 122 237 3 61 89 69 3 61 161 94 3 24 89 50 3 109 25 35 3 27 34 152 3 444 443 435 3 94 35 153 3 3 61 69 3 24 69 89 3 38 218 104 3 22 42 39 3 14 24 34 3 290 166 371 3 226 76 224 3 204 197 72 3 82 3 14 3 13 81 23 3 99 13 23 3 23 110 30 3 110 2 30 3 166 265 371 3 90 61 3 3 34 24 50 3 293 167 207 3 80 78 85 3 61 94 164 3 84 238 80 3 4 161 61 3 132 149 64 3 196 22 228 3 59 46 242 3 179 84 80 3 265 96 371 3 52 258 207 3 121 127 141 3 343 168 346 3 232 227 220 3 232 243 227 3 232 246 243 3 57 126 56 3 57 130 126 3 221 232 220 3 4 61 90 3 134 80 85 3 176 217 175 3 4 0 161 3 78 21 50 3 126 130 129 3 56 126 129 3 111 182 201 3 96 70 371 3 89 164 98 3 123 6 55 3 197 87 72 3 416 419 412 3 245 80 179 3 21 78 36 3 61 164 89 3 67 132 64 3 150 149 132 3 384 387 325 3 214 221 112 3 214 233 232 3 221 214 232 3 244 246 232 3 233 244 232 3 244 252 246 3 244 143 119 3 252 244 119 3 127 142 141 3 67 150 132 3 82 90 3 3 112 180 214 3 244 253 143 3 111 201 269 3 37 74 63 3 133 150 67 3 118 133 67 3 133 180 150 3 191 214 180 3 181 191 180 3 191 234 233 3 214 191 233 3 234 244 233 3 234 7 244 3 244 98 253 3 253 98 143 3 216 217 115 3 181 180 133 3 15 16 219 3 254 98 244 3 7 254 244 3 74 11 63 3 14 3 24 3 3 69 24 3 217 216 175 3 85 78 50 3 73 78 80 3 7 98 254 3 105 133 118 3 1 248 196 3 48 241 100 3 42 156 39 3 149 173 344 3 135 133 105 3 106 135 105 3 31 7 234 3 148 31 234 3 89 98 7 3 31 89 7 3 235 84 230 3 14 27 236 3 106 125 135 3 19 20 62 3 131 54 159 3 34 50 21 3 82 14 236 3 201 52 43 3 310 308 280 3 131 159 54 3 271 310 280 3 27 14 34 3 177 89 31 3 238 73 80 3 130 176 175 3 354 331 381 3 129 130 175 3 125 136 135 3 251 52 201 3 106 56 125 3 56 129 136 3 125 56 136 3 129 175 174 3 136 129 174 3 175 216 215 3 174 175 215 3 115 114 215 3 216 115 215 3 134 85 31 3 85 177 31 3 50 89 177 3 85 50 177 3 179 80 245 3 400 407 367 3 263 83 121 3 217 179 115 3 149 132 64 3 178 187 116 3 142 178 116 3 326 120 319 3 57 83 267 3 304 391 294 3 355 354 359 3 128 29 11 3 267 273 130 3 48 16 10 3 301 302 266 3 196 66 22 3 230 84 217 3 247 13 243 3 110 81 13 3 271 178 266 3 110 13 247 3 278 277 267 3 48 10 329 3 258 11 275 3 1 196 228 3 154 247 243 3 154 110 247 3 263 141 270 3 154 60 110 3 60 154 110 3 154 60 110 3 11 74 37 3 274 5 51 3 252 154 243 3 119 252 243 3 109 110 60 3 39 2 110 3 109 39 110 3 32 128 29 3 32 128 11 3 309 300 311 3 252 119 154 3 73 145 255 3 67 64 259 3 32 29 128 3 258 275 43 3 154 119 60 3 119 109 60 3 137 256 248 3 270 267 83 3 235 238 84 3 267 130 57 3 258 32 11 3 302 310 271 3 51 238 235 3 266 302 271 3 5 36 255 3 51 235 230 3 51 145 73 3 286 51 230 3 287 274 286 3 119 25 109 3 10 40 289 3 120 48 329 3 274 51 286 3 276 230 217 3 10 16 15 3 51 5 145 3 43 11 201 3 176 276 217 3 143 25 119 3 158 207 167 3 360 321 357 3 130 273 276 3 122 198 237 3 270 278 267 3 77 218 38 3 15 6 40 3 280 187 178 3 271 280 178 3 258 207 32 3 66 58 22 3 279 287 278 3 155 139 172 3 121 141 263 3 288 41 274 3 287 288 274 3 276 176 130 3 289 288 205 3 274 41 5 3 288 287 279 3 329 10 289 3 16 100 219 3 127 178 142 3 273 267 276 3 252 119 243 3 116 279 141 3 41 123 5 3 116 288 279 3 142 116 141 3 207 158 32 3 276 277 230 3 101 102 163 3 299 298 294 3 287 286 278 3 5 255 145 3 131 159 70 3 275 11 43 3 32 158 250 3 205 288 116 3 73 36 78 3 120 329 319 3 297 391 300 3 84 179 217 3 17 77 38 3 255 36 73 3 263 270 83 3 249 248 1 3 286 230 277 3 11 37 66 3 43 52 258 3 267 277 276 3 279 278 270 3 141 279 270 3 51 73 238 3 47 36 5 3 201 66 269 3 201 11 66 3 309 310 302 3 300 309 302 3 182 33 251 3 278 286 277 3 243 246 252 3 416 427 419 3 96 131 70 3 66 256 111 3 65 335 189 3 113 374 407 3 144 139 155 3 226 224 139 3 358 400 396 3 30 91 203 3 226 139 144 3 46 328 242 3 307 304 298 3 70 159 54 3 103 265 284 3 443 261 446 3 17 38 28 3 88 200 239 3 72 170 211 3 138 17 28 3 35 1 228 3 295 299 294 3 18 131 140 3 18 59 131 3 207 258 52 3 188 70 54 3 104 87 197 3 222 48 120 3 325 326 311 3 326 281 120 3 54 159 292 3 386 299 295 3 138 59 17 3 48 100 16 3 59 242 17 3 296 121 83 3 10 15 40 3 242 91 17 3 225 9 211 3 314 322 384 3 326 325 281 3 170 225 211 3 17 91 77 3 144 76 226 3 155 9 225 3 159 131 28 3 172 139 170 3 131 138 28 3 281 264 120 3 264 222 120 3 139 155 225 3 139 225 170 3 314 325 313 3 386 295 390 3 292 159 28 3 132 149 344 3 424 427 416 3 49 335 65 3 314 313 304 3 111 269 66 3 9 71 72 3 211 9 72 3 306 316 353 3 307 314 304 3 325 311 313 3 40 41 288 3 289 40 288 3 40 6 41 3 6 123 41 3 22 39 109 3 165 312 76 3 299 307 298 3 144 165 76 3 312 107 76 3 376 381 331 3 165 107 312 3 155 172 330 3 35 228 22 3 45 184 160 3 42 62 156 3 2 39 62 3 58 42 22 3 49 71 9 3 280 116 187 3 280 205 116 3 155 330 144 3 280 289 205 3 319 280 308 3 162 77 20 3 20 77 91 3 329 289 280 3 319 329 280 3 156 62 39 3 372 408 375 3 190 1 0 3 1 35 0 3 42 19 62 3 35 161 0 3 190 0 97 3 35 22 109 3 76 53 224 3 161 35 94 3 49 9 155 3 224 49 155 3 29 63 11 3 160 162 19 3 76 333 53 3 153 25 143 3 71 49 65 3 2 20 30 3 62 20 2 3 55 8 5 3 169 0 4 3 6 8 55 3 35 25 153 3 160 218 162 3 218 77 162 3 15 334 6 3 334 8 6 3 332 76 93 3 8 47 5 3 98 153 143 3 94 153 98 3 219 334 15 3 332 333 76 3 93 76 107 3 100 334 219 3 160 19 45 3 19 162 20 3 340 132 344 3 45 19 42 3 27 47 8 3 27 36 47 3 80 115 179 3 45 42 58 3 71 184 45 3 236 27 8 3 334 236 8 3 332 93 333 3 27 152 36 3 223 64 340 3 236 334 117 3 152 21 36 3 134 148 115 3 115 148 114 3 152 34 21 3 5 123 55 3 337 68 191 3 333 93 282 3 256 66 196 3 135 174 347 3 183 180 195 3 117 285 236 3 182 111 63 3 354 318 352 3 114 234 68 3 71 65 184 3 135 136 174 3 191 215 337 3 337 215 114 3 63 33 182 3 133 135 181 3 135 347 181 3 110 23 81 3 157 180 183 3 149 157 183 3 227 147 220 3 12 23 30 3 151 99 46 3 174 215 191 3 99 328 46 3 114 148 234 3 149 150 157 3 220 147 284 3 79 186 336 3 68 234 191 3 396 357 356 3 99 23 12 3 328 99 12 3 337 114 68 3 356 358 396 3 338 343 342 3 223 340 339 3 265 103 96 3 341 223 339 3 347 174 191 3 182 251 201 3 134 115 80 3 12 30 203 3 345 343 338 3 147 227 103 3 33 108 251 3 95 20 91 3 181 347 191 3 345 346 343 3 157 150 180 3 103 227 18 3 66 240 58 3 345 344 346 3 146 32 108 3 445 125 444 3 30 95 91 3 124 373 374 3 137 249 72 3 344 345 338 3 344 168 346 3 12 203 328 3 284 147 103 3 240 66 37 3 344 173 168 3 314 384 322 3 107 282 93 3 76 53 107 3 107 53 282 3 282 53 333 3 165 76 107 3 315 202 291 3 165 144 76 3 407 374 367 3 144 53 76 3 388 389 92 3 155 144 330 3 144 224 53 3 432 431 434 3 155 189 144 3 144 189 224 3 189 335 53 3 224 189 53 3 146 29 32 3 382 88 209 3 331 316 350 3 331 353 316 3 357 367 366 3 360 357 366 3 367 374 373 3 366 367 373 3 373 407 374 3 388 92 169 3 170 65 155 3 155 65 189 3 328 203 91 3 413 421 414 3 356 331 358 3 242 328 91 3 168 343 346 3 113 198 122 3 124 113 122 3 239 200 315 3 331 356 357 3 372 26 102 3 375 372 102 3 26 163 102 3 408 372 375 3 72 87 65 3 170 72 65 3 87 184 65 3 63 108 11 3 63 29 108 3 370 285 231 3 389 370 231 3 131 18 140 3 33 63 108 3 368 306 321 3 374 113 124 3 285 324 268 3 231 285 268 3 336 272 186 3 224 155 139 3 363 369 372 3 86 193 163 3 208 63 111 3 380 305 202 3 356 357 321 3 346 354 352 3 346 168 354 3 168 359 354 3 364 290 369 3 363 364 369 3 290 371 372 3 369 290 372 3 371 70 26 3 372 371 26 3 70 188 26 3 188 54 26 3 54 163 26 3 54 86 163 3 54 28 86 3 28 38 86 3 38 197 86 3 38 104 197 3 104 218 87 3 218 160 87 3 160 184 87 3 58 240 208 3 240 37 63 3 208 240 63 3 340 64 132 3 343 168 346 3 400 367 357 3 396 400 357 3 54 292 28 3 96 103 18 3 346 168 343 3 249 137 248 3 200 209 199 3 79 222 281 3 327 308 309 3 343 346 352 3 383 388 169 3 200 88 209 3 285 186 324 3 241 48 79 3 16 100 79 3 303 100 79 3 323 105 451 3 100 303 186 3 100 16 79 3 321 353 331 3 236 285 370 3 389 231 92 3 100 285 117 3 108 63 11 3 186 303 79 3 88 382 209 3 82 236 389 3 100 241 79 3 45 72 71 3 0 169 97 3 45 137 72 3 285 100 186 3 137 45 58 3 199 378 305 3 208 137 58 3 356 331 357 3 305 380 202 3 378 349 305 3 169 92 315 3 192 262 75 3 361 192 75 3 291 202 237 3 258 293 207 3 272 79 377 3 324 186 268 3 268 186 88 3 90 389 388 3 169 315 291 3 97 169 291 3 79 320 377 3 4 383 169 3 379 317 368 3 200 202 315 3 92 239 315 3 306 353 321 3 370 389 236 3 48 222 79 3 206 361 185 3 361 206 185 3 92 231 239 3 356 321 331 3 190 171 185 3 249 190 185 3 206 198 361 3 198 192 361 3 90 388 383 3 305 124 237 3 327 311 326 3 4 90 383 3 190 249 1 3 206 361 185 3 171 206 185 3 202 305 237 3 108 29 146 3 308 310 309 3 334 100 117 3 90 82 389 3 79 336 186 3 224 53 335 3 354 381 318 3 231 268 239 3 186 272 209 3 88 186 209 3 200 199 202 3 327 326 319 3 308 327 319 3 309 311 327 3 435 443 446 3 199 305 202 3 97 171 190 3 171 97 206 3 97 291 206 3 237 198 206 3 291 237 206 3 406 124 305 3 399 402 400 3 373 374 407 3 300 304 311 3 304 313 311 3 407 213 113 3 208 111 256 3 403 402 399 3 363 403 399 3 29 128 32 3 403 375 402 3 363 399 359 3 194 192 198 3 193 86 75 3 400 213 407 3 272 336 79 3 79 281 320 3 300 302 297 3 294 298 304 3 299 322 314 3 307 299 314 3 322 384 314 3 377 281 325 3 387 377 325 3 281 377 320 3 355 358 331 3 101 102 262 3 363 375 403 3 197 204 75 3 102 101 262 3 299 384 322 3 262 163 193 3 318 343 352 3 299 322 384 3 299 393 322 3 322 393 384 3 137 208 256 3 86 197 75 3 186 79 336 3 222 264 281 3 185 361 75 3 365 360 366 3 386 392 393 3 299 386 393 3 393 392 384 3 392 394 384 3 394 398 387 3 384 394 387 3 404 377 387 3 398 404 387 3 404 209 377 3 209 272 377 3 399 400 358 3 359 399 358 3 101 163 262 3 262 193 75 3 102 101 375 3 204 72 249 3 31 148 134 3 424 437 427 3 359 358 355 3 400 402 213 3 204 249 185 3 351 317 386 3 390 351 386 3 317 392 386 3 392 317 394 3 317 395 394 3 395 397 398 3 394 395 398 3 397 405 404 3 398 397 404 3 199 209 404 3 405 199 404 3 268 88 239 3 75 204 185 3 318 352 354 3 243 18 227 3 397 385 405 3 385 199 405 3 262 192 194 3 101 262 194 3 18 131 96 3 349 378 199 3 385 349 199 3 250 158 167 3 293 250 167 3 379 362 395 3 317 379 395 3 395 362 397 3 362 365 397 3 365 401 397 3 401 349 385 3 397 401 385 3 375 194 213 3 213 194 113 3 375 101 194 3 354 352 318 3 342 343 318 3 375 213 402 3 451 261 443 3 32 250 293 3 258 32 293 3 113 194 198 3 351 409 368 3 355 331 354 3 339 340 344 3 372 375 363 3 339 344 338 3 368 321 379 3 360 362 379 3 360 365 362 3 366 365 362 3 365 366 362 3 406 349 401 3 365 406 401 3 108 258 52 3 258 108 32 3 305 349 406 3 297 302 301 3 52 251 108 3 321 360 379 3 384 325 314 3 373 406 365 3 366 373 365 3 373 349 406 3 349 373 406 3 373 124 406 3 106 105 323 3 439 434 431 3 18 243 229 3 83 57 260 3 447 83 260 3 418 425 429 3 439 441 434 3 441 442 434 3 257 106 323 3 391 425 418 3 435 437 444 3 257 323 452 3 391 418 294 3 296 440 441 3 440 296 441 3 131 59 138 3 294 413 295 3 95 30 20 3 428 432 434 3 422 424 415 3 294 420 413 3 425 296 429 3 414 422 415 3 425 121 296 3 296 440 431 3 452 323 451 3 296 83 447 3 431 441 439 3 445 444 436 3 429 296 431 3 450 56 106 3 301 121 433 3 106 257 452 3 414 415 411 3 390 413 386 3 18 229 59 3 59 229 46 3 386 414 411 3 301 433 425 3 248 256 196 3 411 416 412 3 300 391 304 3 422 436 424 3 46 229 151 3 127 121 301 3 412 419 356 3 295 413 390 3 351 390 411 3 442 56 125 3 409 351 412 3 247 243 13 3 330 172 155 3 451 118 67 3 364 44 290 3 290 44 166 3 166 210 265 3 265 210 284 3 442 436 434 3 229 99 151 3 364 449 44 3 449 283 44 3 418 420 294 3 363 449 364 3 212 284 210 3 44 210 166 3 420 428 422 3 44 212 210 3 247 229 243 3 229 247 99 3 127 266 178 3 56 450 260 3 413 420 421 3 359 168 363 3 363 168 449 3 415 424 416 3 296 447 260 3 212 220 284 3 436 437 424 3 351 411 412 3 440 441 431 3 283 212 44 3 451 67 261 3 168 173 449 3 449 173 283 3 426 342 318 3 381 426 318 3 212 348 220 3 266 127 301 3 426 338 342 3 149 283 173 3 149 212 283 3 438 338 426 3 433 121 425 3 149 183 212 3 414 421 422 3 172 170 155 3 368 317 351 3 350 381 376 3 67 259 261 3 183 112 212 3 212 112 348 3 348 112 220 3 432 431 434 3 448 339 338 3 438 448 338 3 420 431 432 3 112 221 220 3 428 420 432 3 431 432 434 3 417 381 350 3 422 428 434 3 423 426 381 3 417 423 381 3 56 260 57 3 451 105 118 3 296 260 440 3 386 413 414 3 306 350 316 3 448 341 339 3 415 416 411 3 436 444 437 3 259 341 448 3 297 425 391 3 442 125 445 3 450 106 452 3 410 350 306 3 341 259 223 3 355 417 350 3 410 355 350 3 259 64 223 3 410 356 350 3 356 410 350 3 356 355 410 3 355 419 417 3 247 13 99 3 195 112 183 3 180 112 195 3 419 355 356 3 301 425 297 3 390 386 411 3 446 259 448 3 446 261 259 3 434 436 422 3 421 420 422 3 409 410 306 3 368 409 306 3 412 356 410 3 409 412 410 3 442 445 436 3 435 423 430 tests/meshes/ply/tet.ply000066400000000000000000000005751456244072500156520ustar00rootroot00000000000000ply format ascii 1.0 comment single tetrahedron with colored faces element vertex 4 comment tetrahedron vertices property float x property float y property float z element face 4 property list uchar int vertex_indices property uchar red property uchar green property uchar blue end_header 0 0 0 0 1 1 1 0 1 1 1 0 3 0 1 2 255 255 255 3 0 2 3 255 0 0 3 0 1 3 0 255 0 3 1 2 3 0 0 255 tests/meshes/su2/000077500000000000000000000000001456244072500142265ustar00rootroot00000000000000tests/meshes/su2/README.md000066400000000000000000000002411456244072500155020ustar00rootroot00000000000000* `square.su2` : from https://su2code.github.io/docs_v7/Mesh-File/ * `mixgrid.su2` : generated using http://ossanworld.com/cfdbooks/cfdcodes/mixgrid_cube_v5.f90 tests/meshes/su2/mixgrid.su2000066400000000000000000000114071456244072500163270ustar00rootroot00000000000000 % % Problem dimension % NDIME= 3 % % Inner element connectivity NELEM= 10 10 2 6 3 11 0 10 6 7 3 11 1 10 14 10 11 6 2 10 14 11 15 6 3 10 2 10 6 11 4 10 6 15 7 11 5 13 4 8 0 5 9 1 6 13 12 8 4 13 9 5 7 13 5 9 1 6 10 2 8 13 13 9 5 14 10 6 9 % % Node coordinates % NPOIN= 16 0.000000000000000E+00 0.000000000000000E+00 0.000000000000000E+00 0.000000000000000E+00 0.000000000000000E+00 1.500000000000000E-01 0.000000000000000E+00 0.000000000000000E+00 3.000000000000000E-01 0.000000000000000E+00 0.000000000000000E+00 1.000000000000000E+00 0.000000000000000E+00 1.000000000000000E+00 0.000000000000000E+00 0.000000000000000E+00 1.000000000000000E+00 1.500000000000000E-01 0.000000000000000E+00 1.000000000000000E+00 3.000000000000000E-01 0.000000000000000E+00 1.000000000000000E+00 1.000000000000000E+00 1.000000000000000E+00 0.000000000000000E+00 0.000000000000000E+00 1.000000000000000E+00 0.000000000000000E+00 1.500000000000000E-01 1.000000000000000E+00 0.000000000000000E+00 3.000000000000000E-01 1.000000000000000E+00 0.000000000000000E+00 1.000000000000000E+00 1.000000000000000E+00 1.000000000000000E+00 0.000000000000000E+00 1.000000000000000E+00 1.000000000000000E+00 1.500000000000000E-01 1.000000000000000E+00 1.000000000000000E+00 3.000000000000000E-01 1.000000000000000E+00 1.000000000000000E+00 1.000000000000000E+00 % % Boundary elements % NMARK= 6 MARKER_TAG= xmin MARKER_ELEMS= 4 5 6 7 3 5 6 3 2 9 0 4 5 1 9 1 5 6 2 MARKER_TAG= xmax MARKER_ELEMS= 4 5 14 10 11 5 14 11 15 9 12 8 9 13 9 13 9 10 14 MARKER_TAG= ymin MARKER_ELEMS= 4 5 2 3 11 5 2 11 10 9 8 0 1 9 9 9 1 2 10 MARKER_TAG= ymax MARKER_ELEMS= 4 5 6 14 15 5 6 15 7 9 4 12 13 5 9 5 13 14 6 MARKER_TAG= zmin MARKER_ELEMS= 2 5 4 0 8 5 4 8 12 MARKER_TAG= zmax MARKER_ELEMS= 2 5 7 15 11 5 7 11 3 tests/meshes/su2/square.su2000066400000000000000000000015331456244072500161630ustar00rootroot00000000000000% % Problem dimension % NDIME= 2 % % Inner element connectivity % NELEM= 8 5 0 1 3 0 5 1 4 3 1 5 1 2 4 2 5 2 5 4 3 5 3 4 6 4 5 4 7 6 5 5 4 5 7 6 5 5 8 7 7 % % Node coordinates % NPOIN= 9 0.00000000000000 0.00000000000000 0 0.50000000000000 0.00000000000000 1 1.00000000000000 0.00000000000000 2 0.00000000000000 0.50000000000000 3 0.50000000000000 0.50000000000000 4 1.00000000000000 0.50000000000000 5 0.00000000000000 1.00000000000000 6 0.50000000000000 1.00000000000000 7 1.00000000000000 1.00000000000000 8 % % Boundary elements % NMARK= 4 MARKER_TAG= lower MARKER_ELEMS= 2 3 0 1 3 1 2 MARKER_TAG= right MARKER_ELEMS= 2 3 2 5 3 5 8 MARKER_TAG= upper MARKER_ELEMS= 2 3 8 7 3 7 6 MARKER_TAG= left MARKER_ELEMS= 2 3 6 3 3 3 0 tests/meshes/tecplot/000077500000000000000000000000001456244072500151675ustar00rootroot00000000000000tests/meshes/tecplot/quad_zone_comma.tec000066400000000000000000000005501456244072500210250ustar00rootroot00000000000000TITLE = "Zone and variables separated by commas" VARIABLES = X, Y, "foo bar", foobar # Random comment ZONE N=4, E =1,ET= QUADRILATERAL , T = "Hex with commas" # Random comment , F = FEBLOCK, VARLOCATION =( [4]= CELLCENTERED ) 0.0 1.0 1.0 0.0 0.0 0.0 1.0 1.0 # Random comment 1.0 2.0 3.0 4.0 # Random comment 42.0 # Random comment 1 2 3 4tests/meshes/tecplot/quad_zone_multivar.tec000066400000000000000000000005571456244072500216030ustar00rootroot00000000000000TITLE = "Zone and variables separated by commas" VARIABLES = "X", "Y", "foo bar", "foobar" # Random comment ZONE N=4, E =1,ET= QUADRILATERAL , T = "Hex with commas" # Random comment , F = FEBLOCK, VARLOCATION =( [4]= CELLCENTERED ) 0.0 1.0 1.0 0.0 0.0 0.0 1.0 1.0 # Random comment 1.0 2.0 3.0 4.0 # Random comment 42.0 # Random comment 1 2 3 4tests/meshes/tecplot/quad_zone_space.tec000066400000000000000000000005421456244072500210250ustar00rootroot00000000000000TITLE = "Zone and variables separated by white spaces" VARIABLES = X Y "foo bar" foobar # Random comment ZONE T = "VARLOCATION" N=4 E =1 ET= QUADRILATERAL # Random comment F = FEBLOCK VARLOCATION =( [4]= CELLCENTERED ) 0.0 1.0 1.0 0.0 0.0 0.0 1.0 1.0 # Random comment 1.0 2.0 3.0 4.0 # Random comment 42.0 # Random comment 1 2 3 4tests/meshes/tetgen/000077500000000000000000000000001456244072500150035ustar00rootroot00000000000000tests/meshes/tetgen/mesh.ele000066400000000000000000000124001456244072500164230ustar00rootroot00000000000000# This file was created by meshio v4.1.0 # attribute names: medit:ref 304 4 1 0 41 35 40 42 2 1 50 36 46 45 2 2 40 54 41 42 2 3 41 54 44 43 2 4 56 40 35 38 2 5 55 51 50 37 2 6 42 35 40 38 2 7 50 51 55 36 2 8 54 41 48 43 2 9 52 56 35 38 2 10 46 36 49 45 2 11 41 48 43 42 2 12 41 54 48 42 2 13 53 55 51 36 2 14 47 49 36 45 2 15 35 42 52 38 2 16 42 40 54 39 2 17 54 48 42 38 2 18 20 56 35 52 2 19 38 56 40 39 2 20 50 55 13 36 2 21 49 43 48 46 2 22 40 42 38 39 2 23 53 51 49 36 2 24 49 0 51 53 2 25 36 51 49 47 2 26 35 40 56 19 2 27 49 16 43 46 2 28 48 54 16 38 2 29 38 42 54 39 2 30 12 55 50 37 2 31 13 55 14 36 2 32 55 51 0 53 2 33 38 54 16 39 2 34 18 56 40 19 2 35 54 44 16 47 2 36 19 56 35 20 2 37 43 48 16 49 2 38 51 55 11 37 2 39 50 13 55 12 2 40 55 12 11 37 2 41 51 16 0 49 2 42 38 16 1 39 2 43 55 53 14 36 2 44 51 55 10 11 2 45 53 0 55 15 2 46 52 20 56 21 2 47 49 51 16 47 2 48 38 1 56 39 2 49 40 56 18 39 2 50 55 53 15 14 2 51 0 51 55 10 2 52 56 18 39 17 2 53 39 1 56 17 2 54 22 1 56 38 2 55 56 52 21 38 2 56 22 56 21 38 2 57 45 47 43 44 2 58 16 43 47 44 2 59 36 45 51 47 2 60 36 51 45 50 2 61 37 51 45 47 2 62 37 45 51 50 2 63 43 45 16 47 2 64 43 16 45 46 2 65 49 16 45 47 2 66 49 45 16 46 2 67 43 16 54 44 2 68 43 54 16 48 2 69 43 48 73 42 1 70 74 41 35 40 1 71 45 50 37 75 1 72 54 44 65 41 1 73 35 62 74 40 1 74 75 45 44 68 1 75 41 74 65 40 1 76 48 77 73 42 1 77 44 74 65 41 1 78 41 65 54 40 1 79 75 37 45 68 1 80 37 50 12 86 1 81 32 46 48 76 1 82 50 37 75 86 1 83 37 47 45 68 1 84 43 44 74 45 1 85 45 47 44 68 1 86 80 46 48 32 1 87 35 41 74 42 1 88 46 36 50 76 1 89 42 63 35 52 1 90 62 40 18 64 1 91 40 35 62 19 1 92 36 46 80 76 1 93 37 11 88 86 1 94 42 77 73 52 1 95 50 46 76 45 1 96 85 36 80 76 1 97 62 65 74 40 1 98 76 46 43 45 1 99 65 44 54 68 1 100 76 50 45 75 1 101 73 77 48 32 1 102 45 44 74 75 1 103 54 44 47 68 1 104 51 67 16 47 1 105 16 71 29 67 1 106 75 12 50 86 1 107 68 75 37 86 1 108 32 48 73 76 1 109 43 74 41 42 1 110 44 27 75 68 1 111 40 18 64 39 1 112 37 88 51 28 1 113 76 85 36 87 1 114 67 16 71 51 1 115 65 27 44 68 1 116 73 35 74 42 1 117 49 82 0 53 1 118 41 44 74 43 1 119 67 66 16 47 1 120 19 35 62 25 1 121 70 2 60 29 1 122 60 66 70 29 1 123 66 60 2 29 1 124 76 36 50 87 1 125 79 72 30 49 1 126 43 74 76 45 1 127 57 60 39 70 1 128 77 61 73 52 1 129 65 27 74 44 1 130 34 83 8 79 1 131 4 26 78 59 1 132 65 54 40 39 1 133 43 73 74 42 1 134 80 48 77 32 1 135 27 74 44 75 1 136 35 74 62 25 1 137 40 62 23 64 1 138 53 14 36 85 1 139 86 88 37 28 1 140 73 63 35 42 1 141 79 30 78 49 1 142 51 16 71 81 1 143 66 39 60 70 1 144 50 33 12 75 1 145 29 66 16 67 1 146 52 77 61 38 1 147 66 54 16 47 1 148 71 70 16 29 1 149 23 40 64 39 1 150 80 46 32 76 1 151 71 67 51 84 1 152 73 63 42 52 1 153 60 57 2 70 1 154 16 78 69 72 1 155 69 78 30 72 1 156 85 80 9 76 1 157 16 48 38 78 1 158 11 88 51 37 1 159 83 72 8 79 1 160 60 2 23 66 1 161 54 39 66 70 1 162 69 38 16 58 1 163 84 7 67 28 1 164 36 34 53 85 1 165 38 78 59 69 1 166 72 16 78 49 1 167 78 38 16 69 1 168 59 78 4 69 1 169 72 78 30 49 1 170 69 59 38 58 1 171 39 54 16 70 1 172 84 51 71 81 1 173 9 85 76 87 1 174 63 73 61 52 1 175 47 37 51 68 1 176 8 82 72 83 1 177 68 6 75 86 1 178 65 3 62 74 1 179 58 16 69 70 1 180 0 16 51 81 1 181 36 53 34 80 1 182 16 48 78 49 1 183 66 16 54 70 1 184 43 74 73 76 1 185 70 66 16 29 1 186 65 62 23 40 1 187 80 9 34 85 1 188 35 25 63 73 1 189 45 74 76 75 1 190 72 82 16 49 1 191 74 3 62 25 1 192 87 76 9 33 1 193 40 23 65 39 1 194 67 71 7 84 1 195 15 53 83 14 1 196 57 1 16 39 1 197 1 16 38 58 1 198 32 9 80 76 1 199 82 0 16 49 1 200 25 35 74 73 1 201 31 81 71 72 1 202 49 53 36 80 1 203 72 30 8 79 1 204 75 27 6 68 1 205 53 83 82 15 1 206 75 6 33 86 1 207 2 57 24 70 1 208 86 68 6 28 1 209 50 76 33 75 1 210 39 16 57 70 1 211 49 36 46 80 1 212 37 68 86 28 1 213 1 16 58 70 1 214 68 37 51 28 1 215 82 31 8 72 1 216 3 65 27 74 1 217 30 4 78 69 1 218 26 61 5 77 1 219 29 71 7 67 1 220 63 25 5 73 1 221 34 36 80 85 1 222 21 52 61 38 1 223 82 16 0 72 1 224 81 71 7 31 1 225 38 48 77 78 1 226 33 12 75 86 1 227 47 66 54 68 1 228 66 65 54 68 1 229 67 51 84 88 1 230 65 54 39 66 1 231 39 60 64 66 1 232 67 51 88 28 1 233 24 58 69 70 1 234 48 49 46 80 1 235 78 48 77 80 1 236 51 67 47 68 1 237 84 71 7 81 1 238 57 16 1 70 1 239 77 73 5 32 1 240 14 53 34 85 1 241 62 23 3 65 1 242 13 50 36 87 1 243 58 69 4 24 1 244 31 0 81 72 1 245 63 19 35 20 1 246 47 67 66 68 1 247 53 82 0 15 1 248 82 0 31 72 1 249 60 23 64 66 1 250 13 50 87 12 1 251 1 58 24 70 1 252 50 76 87 33 1 253 24 57 1 70 1 254 77 26 61 38 1 255 20 35 63 52 1 256 51 67 68 28 1 257 61 73 5 77 1 258 88 84 67 28 1 259 48 78 49 80 1 260 4 59 69 58 1 261 22 38 59 58 1 262 21 22 38 59 1 263 70 16 69 72 1 264 77 26 38 78 1 265 39 23 65 66 1 266 73 5 63 61 1 267 39 64 23 66 1 268 78 79 49 80 1 269 39 60 57 17 1 270 78 26 38 59 1 271 53 34 83 14 1 272 21 61 26 38 1 273 57 1 39 17 1 274 33 87 50 12 1 275 25 19 35 63 1 276 84 10 51 81 1 277 38 22 1 58 1 278 71 16 70 72 1 279 85 13 36 87 1 280 10 0 51 81 1 281 14 13 36 85 1 282 38 26 21 59 1 283 51 10 84 88 1 284 88 51 10 11 1 285 64 60 39 17 1 286 52 61 20 21 1 287 18 40 62 19 1 288 12 11 37 86 1 289 20 63 61 52 1 290 18 64 39 17 1 291 76 48 43 46 1 292 76 43 48 73 1 293 42 38 77 52 1 294 77 38 42 48 1 295 79 49 83 72 1 296 82 83 49 72 1 297 82 49 83 53 1 298 81 16 72 0 1 299 81 72 16 71 1 300 49 83 80 79 1 301 49 80 83 53 1 302 34 80 83 79 1 303 34 83 80 53 1 tests/meshes/tetgen/mesh.node000066400000000000000000000210241456244072500166050ustar00rootroot00000000000000# This file was created by meshio v4.1.0 # attribute and marker names: moje_data, medit:ref 89 3 1 1 0 1.0000000000000000e+00 5.0000000000000000e-01 6.9999998807907104e-01 0.0000000000000000e+00 0 1 0.0000000000000000e+00 5.0000000000000000e-01 6.9999998807907104e-01 0.0000000000000000e+00 0 2 0.0000000000000000e+00 0.0000000000000000e+00 1.0000000000000000e+00 0.0000000000000000e+00 1 3 0.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 0 4 0.0000000000000000e+00 1.0000000000000000e+00 1.0000000000000000e+00 0.0000000000000000e+00 1 5 0.0000000000000000e+00 1.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 0 6 1.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 0 7 1.0000000000000000e+00 0.0000000000000000e+00 1.0000000000000000e+00 0.0000000000000000e+00 1 8 1.0000000000000000e+00 1.0000000000000000e+00 1.0000000000000000e+00 0.0000000000000000e+00 1 9 1.0000000000000000e+00 1.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 0 10 1.0000000000000000e+00 3.4363371133804321e-01 6.2469798326492310e-01 0.0000000000000000e+00 0 11 1.0000000000000000e+00 3.0501440167427063e-01 4.5549580454826355e-01 0.0000000000000000e+00 0 12 1.0000000000000000e+00 4.1322329640388489e-01 3.1980618834495544e-01 0.0000000000000000e+00 0 13 1.0000000000000000e+00 5.8677667379379272e-01 3.1980618834495544e-01 0.0000000000000000e+00 0 14 1.0000000000000000e+00 6.9498562812805176e-01 4.5549580454826355e-01 0.0000000000000000e+00 0 15 1.0000000000000000e+00 6.5636628866195679e-01 6.2469798326492310e-01 0.0000000000000000e+00 0 16 5.0000000000000000e-01 5.0000000000000000e-01 6.9999998807907104e-01 0.0000000000000000e+00 0 17 0.0000000000000000e+00 3.4363371133804321e-01 6.2469798326492310e-01 0.0000000000000000e+00 0 18 0.0000000000000000e+00 3.0501440167427063e-01 4.5549580454826355e-01 0.0000000000000000e+00 0 19 0.0000000000000000e+00 4.1322329640388489e-01 3.1980618834495544e-01 0.0000000000000000e+00 0 20 0.0000000000000000e+00 5.8677667379379272e-01 3.1980618834495544e-01 0.0000000000000000e+00 0 21 0.0000000000000000e+00 6.9498562812805176e-01 4.5549580454826355e-01 0.0000000000000000e+00 0 22 0.0000000000000000e+00 6.5636628866195679e-01 6.2469798326492310e-01 0.0000000000000000e+00 0 23 0.0000000000000000e+00 0.0000000000000000e+00 5.0000000000000000e-01 0.0000000000000000e+00 0 24 0.0000000000000000e+00 5.0000000000000000e-01 1.0000000000000000e+00 0.0000000000000000e+00 1 25 0.0000000000000000e+00 5.0000000000000000e-01 0.0000000000000000e+00 0.0000000000000000e+00 0 26 0.0000000000000000e+00 1.0000000000000000e+00 5.0000000000000000e-01 0.0000000000000000e+00 0 27 5.0000000000000000e-01 0.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 0 28 1.0000000000000000e+00 0.0000000000000000e+00 5.0000000000000000e-01 0.0000000000000000e+00 0 29 5.0000000000000000e-01 0.0000000000000000e+00 1.0000000000000000e+00 0.0000000000000000e+00 1 30 5.0000000000000000e-01 1.0000000000000000e+00 1.0000000000000000e+00 0.0000000000000000e+00 1 31 1.0000000000000000e+00 5.0000000000000000e-01 1.0000000000000000e+00 0.0000000000000000e+00 1 32 5.0000000000000000e-01 1.0000000000000000e+00 0.0000000000000000e+00 0.0000000000000000e+00 0 33 1.0000000000000000e+00 5.0000000000000000e-01 0.0000000000000000e+00 0.0000000000000000e+00 0 34 1.0000000000000000e+00 1.0000000000000000e+00 5.0000000000000000e-01 0.0000000000000000e+00 0 35 1.5536570549011230e-01 4.9953359365463257e-01 3.0000048875808716e-01 0.0000000000000000e+00 0 36 8.1072819232940674e-01 6.6186362504959106e-01 3.8252589106559753e-01 0.0000000000000000e+00 0 37 8.3570951223373413e-01 3.4318828582763672e-01 3.7586259841918945e-01 0.0000000000000000e+00 0 38 1.4899100363254547e-01 6.9498562812805176e-01 5.4450422525405884e-01 0.0000000000000000e+00 0 39 1.4899100363254547e-01 3.0501440167427063e-01 5.4450422525405884e-01 0.0000000000000000e+00 0 40 1.6211509704589844e-01 3.4222349524497986e-01 3.7709110975265503e-01 0.0000000000000000e+00 0 41 3.1894388794898987e-01 4.1364109516143799e-01 3.1960558891296387e-01 0.0000000000000000e+00 0 42 3.0048260092735291e-01 5.9788781404495239e-01 3.2559248805046082e-01 0.0000000000000000e+00 0 43 4.7484621405601501e-01 5.1894259452819824e-01 3.0089908838272095e-01 0.0000000000000000e+00 0 44 4.8751631379127502e-01 3.6032208800315857e-01 3.5685640573501587e-01 0.0000000000000000e+00 0 45 6.5104299783706665e-01 4.2482939362525940e-01 3.1466409564018250e-01 0.0000000000000000e+00 0 46 6.4090651273727417e-01 6.1140972375869751e-01 3.3390399813652039e-01 0.0000000000000000e+00 0 47 6.5412777662277222e-01 3.0226328969001770e-01 4.6999689936637878e-01 0.0000000000000000e+00 0 48 4.3121519684791565e-01 6.9295471906661987e-01 4.4738370180130005e-01 0.0000000000000000e+00 0 49 6.4405417442321777e-01 6.9429111480712891e-01 5.4744458198547363e-01 0.0000000000000000e+00 0 50 8.2820540666580200e-01 5.0739651918411255e-01 3.0013680458068848e-01 0.0000000000000000e+00 0 51 8.2212162017822266e-01 3.0967760086059570e-01 5.6146049499511719e-01 0.0000000000000000e+00 0 52 1.1974179744720459e-01 6.4263367652893066e-01 3.5980150103569031e-01 0.0000000000000000e+00 0 53 8.5100901126861572e-01 6.9498562812805176e-01 5.4450422525405884e-01 0.0000000000000000e+00 0 54 3.2907238602638245e-01 3.0151790380477905e-01 4.7540658712387085e-01 0.0000000000000000e+00 0 55 1.0000000000000000e+00 5.0000000000000000e-01 5.0000000000000000e-01 0.0000000000000000e+00 0 56 0.0000000000000000e+00 5.0000000000000000e-01 5.0000000000000000e-01 0.0000000000000000e+00 0 57 0.0000000000000000e+00 3.5660341382026672e-01 7.9776620864868164e-01 0.0000000000000000e+00 0 58 0.0000000000000000e+00 6.4339661598205566e-01 7.9776620864868164e-01 0.0000000000000000e+00 0 59 0.0000000000000000e+00 8.3515560626983643e-01 7.2511637210845947e-01 0.0000000000000000e+00 0 60 0.0000000000000000e+00 1.7500209808349609e-01 7.0604157447814941e-01 0.0000000000000000e+00 0 61 0.0000000000000000e+00 7.7878558635711670e-01 2.8744849562644958e-01 0.0000000000000000e+00 0 62 0.0000000000000000e+00 2.4160820245742798e-01 2.9393941164016724e-01 0.0000000000000000e+00 0 63 0.0000000000000000e+00 6.4330238103866577e-01 1.7870600521564484e-01 0.0000000000000000e+00 0 64 0.0000000000000000e+00 1.9976480305194855e-01 5.5565208196640015e-01 0.0000000000000000e+00 0 65 2.5000000000000000e-01 0.0000000000000000e+00 2.5000000000000000e-01 0.0000000000000000e+00 0 66 3.7500000000000000e-01 0.0000000000000000e+00 6.2500000000000000e-01 0.0000000000000000e+00 0 67 7.1875000000000000e-01 0.0000000000000000e+00 7.1875000000000000e-01 0.0000000000000000e+00 0 68 6.5429687500000000e-01 0.0000000000000000e+00 3.4570309519767761e-01 0.0000000000000000e+00 0 69 2.5000000000000000e-01 7.5000000000000000e-01 1.0000000000000000e+00 0.0000000000000000e+00 1 70 3.7500000000000000e-01 3.7500000000000000e-01 1.0000000000000000e+00 0.0000000000000000e+00 1 71 7.1875000000000000e-01 2.8125000000000000e-01 1.0000000000000000e+00 0.0000000000000000e+00 1 72 6.5429687500000000e-01 6.5429687500000000e-01 1.0000000000000000e+00 0.0000000000000000e+00 1 73 2.5000000000000000e-01 7.5000000000000000e-01 0.0000000000000000e+00 0.0000000000000000e+00 0 74 3.7500000000000000e-01 3.7500000000000000e-01 0.0000000000000000e+00 0.0000000000000000e+00 0 75 7.1875000000000000e-01 2.8125000000000000e-01 0.0000000000000000e+00 0.0000000000000000e+00 0 76 6.5429687500000000e-01 6.5429687500000000e-01 0.0000000000000000e+00 0.0000000000000000e+00 0 77 2.5000000000000000e-01 1.0000000000000000e+00 2.5000000000000000e-01 0.0000000000000000e+00 0 78 3.7500000000000000e-01 1.0000000000000000e+00 6.2500000000000000e-01 0.0000000000000000e+00 0 79 7.1875000000000000e-01 1.0000000000000000e+00 7.1875000000000000e-01 0.0000000000000000e+00 0 80 6.5429687500000000e-01 1.0000000000000000e+00 3.4570309519767761e-01 0.0000000000000000e+00 0 81 1.0000000000000000e+00 3.5660341382026672e-01 7.9776620864868164e-01 0.0000000000000000e+00 0 82 1.0000000000000000e+00 6.4339661598205566e-01 7.9776620864868164e-01 0.0000000000000000e+00 0 83 1.0000000000000000e+00 8.3515560626983643e-01 7.2511637210845947e-01 0.0000000000000000e+00 0 84 1.0000000000000000e+00 1.7500209808349609e-01 7.0604157447814941e-01 0.0000000000000000e+00 0 85 1.0000000000000000e+00 7.7878558635711670e-01 2.8744849562644958e-01 0.0000000000000000e+00 0 86 1.0000000000000000e+00 2.4160820245742798e-01 2.9393941164016724e-01 0.0000000000000000e+00 0 87 1.0000000000000000e+00 6.4330238103866577e-01 1.7870600521564484e-01 0.0000000000000000e+00 0 88 1.0000000000000000e+00 1.9976480305194855e-01 5.5565208196640015e-01 0.0000000000000000e+00 0 tests/meshes/ugrid/000077500000000000000000000000001456244072500146275ustar00rootroot00000000000000tests/meshes/ugrid/hch_strct.4.lb8.ugrid000066400000000000000000000431641456244072500205020ustar00rootroot000000000000002 `?,ٓe?՟&>?՟&>?,ٓe?՟&>??՟&>?ffffff?;?$WL6|u?ffffff?#WL6|ffffff?;? WL6|u?ffffff?#WL6|?9G?:1ک?!ڝ9G?!ڭ9G?;1ک?!ڝ?9G?!ڭ?dx?:1ک?!ڝdx?!ڭdx?;1ک?!ڝ?dx?!ڭ?Cš3*? 2g?̾@3*?̾@ili?m?Fi?F1㑩?61H?JvL_㑩?JvL_zEO&OB}? Ϣ?j&OB}?jQC 1jl 2?@A?  2?JA$ o#1o˧?"I?aħo#1o˧?aħVKѭY?!8W0b?Ie"cѭY?Ie"cJVPULh"N F?IvhPULhGvhdxǿ\&з1WXx?ʧ8,\&зȧ8,Ŀo^}ݿNWu:Կ&ĺ)?lĿMWu:ԿlԿHF`뿾7i3?AֿF`AT'}crˌM?꿼}cr-7g F})o @@m7[3F>m7[3~%p0uqH/*yp!@2wqH/*2#*,RD"Dg@n{4@Ĉ͋ ("Dg@ˆ͋ 8X#qT5OsI@4]c=#qT1]cM3*? 2g?̾@?i?m?F?㑩?61H?JvL_?&OB}? Ϣ?j? 2?BA??o#1o˧?$I?aħ?ѭY?#8W0b?Ie"c?PULh"N F?Dvh?\&з1WXx?Ƨ8,?NWu:Կ'ĺ)?l?F`7i3?~A?}crˌM??F})o @=m7[3@uqH/*zp!@2@"Dg@n{4@͋ (@#qT7OsI@0]c=@.3*?̾@?~?F?㑩?jJvL_?OB}?`? 2?U?!1o˧?`ħ?寫Y?- e"c? VLhv0h?E]&з8,?u:Կλl?]m`]A?lcr,?NF,l7[3@sH/*2#@Dg@͋ 8@#qT4]cM@`͉]?Lif?yݫR?aKuLif?aK=F?EJrf?ʆO?KJ:uEJrf?IJ:ܭOA?C8f?Ir1!?WbW8>vC8f?UbW8>ܽ?j,g?'ZK?j6owj,g?h6o\5?Z++Gh?-R-?GݙK|Z++Gh?GݙKH.? `ufx?L a֤?2 `ufx?2-Ivz?F9'?U?>R F9'?>R m5?7?[?87?8= ?vt?Ms&?X@vt?W@Ûu_?n)?.?Mhx¿n)?Mhxҿ @']??9!տ']?9!T'@RKn @Z(6?nRKn @n-7g @^)@-. @^)@~%p1@JnN,@{O!@ ؤLnN,@ ؤ#*,D@+Ψt@@xz4@[U(+Ψt@@YU8 Y@"qYT@6OsI@4]c="qYT@3]cMLif?yݫR?aKu?EJrf?ʆO?FJ:u?C8f?Ir1!?RbW8>v?j,g?'ZK?e6ow?Z++Gh?-R-?GݙK|? `ufx?L a֤?2?F9'?U??,g?D'4o?\Hh? K?:yfx?q¢2?Po+? ?\7?@iq?|t?{/ @? )?mILhx?_? ?>TKn @ٍn?n*@@oN,@ ؤ#@Bڨt@@U8@"qYT@3]cM@9G?8X>kܩ?Gnܝ9G?Gnܭ9G?vRp?zV㝿9G?xV㭿9G?8fa:?:9G?89G?,|9G?( xW9G?& xW9G?bd?˵PZ9G?ɵPZ# l?Ю?Xʡ# l?Wʱ i? c?B-=c i?B-=c ?K?tSȰ ?tSJ|?(v^?v sJ|?t sο:-п?T Ѫ?q8Ͽ:-п?q8߿؂(g ?ODp8Ԃ(NDp8(Ntۯ@(N.p9/@_s& .]s&aʑgZ}s+@܁haʑgفh/(Y@@ \q3( \qC:f>NJT@hb G:f>gb W9G?9X>kܩ?Gnܝ?9G?vRp?tV?9G?9fa:?4?9G?-|9G?" xW?9G?bd?ŵPZ?# l?Ю?Uʡ? i? c?B-=c? ?K?rSȰ?K|?(v^?p s?:-п?V Ѫ?q8?Ԃ( g ?LDp8?(Ntۯ@?.r9/@[s& @aʑg]}s+@ׁh@(Y@@ \q3@:f>NJT@eb G@9G?Gnܭ?9G?xV?9G?8?9G?& xW?9G?ɵPZ?# l?Wʱ? i?B-=c? ?tS?J|?t s?:-п?q8?Ԃ(NDp8?(N@.]s&@aʑgفh/@( \qC@:f>gb W@dx?8X>kܩ?Gnܝdx?Gnܭdx?vRp?zV㝿dx?xV㭿dx?8fa:?:dx?8dx?,|9G?( xWdx?& xWdx?bd?˵PZdx?ɵPZqnɣ?Ю?Xʡqnɣ?Wʱz? c?B-=cz?B-=c;?K?tSȰ;?tSQ|S?(v^?v sQ|S?u sο-B?T Ѫ?q8Ͽ-B?q8߿,80P?g ?ODp8-80P?ODp8['de?tۯ@['de?Lvy\@p9/@`s& Lvy\@_s&aʑg@[}s+@݁haʑg@ہh/*@Y@@ \q3*@ \qC:f?@NJT@ib G:f?@hb Wdx?9X>kܩ?Gnܝ?dx?vRp?tV?dx?9fa:?4?dx?-|9G?" xW?dx?bd?ŵPZ?qnɣ?Ю?Uʡ?z? c?B-=c?;?K?rSȰ?Q|S?(v^?r s?-B?X Ѫ?q8?-80P?!g ?NDp8?['de?tۯ@?Lvy\@s9/@]s& @aʑg@^}s+@فh@*@Y@@ \q3@:f?@NJT@fb G@dx?Gnܭ?dx?xV?dx?8?dx?& xW?dx?ɵPZ?qnɣ?Wʱ?z?B-=c?;?tS?Q|S?u s?-B?q8?-80P?ODp8?['de?@Lvy\@_s&@aʑg@ہh/@*@ \qC@:f?@hb W@   BA@AR@Rb@       ABRAbR""2"2"!!$""$'%%'*((*-++-0..0311364469779<::<?==?B@ !!$$''**--00336699<<??B     eehhkknnqqttwwzz}}    ceecfhhfikkilnnloqqorttruwwuxzzx{}}{~~STSUTVUWV"XW"%YX%(ZY(+[Z+.\[.1]\14^]47_^7:`_:=a`=@baSSTTUUVVWWXXYYZZ[[\\]]^^__``aab#$#%$&%'&(')(*)+*,+-,.-/.0/1021# #$$%%&&''(())**++,,--..//00112 cfcifliolrourxu{x~{~ ! !"#$"#$%&'%&'()*()*+,-+,-./0./0123123456456789789:;<:;<=>?=>?@ABCCDDEEFFG G "H#"H#%I&%I&(J)(J)+K,+K,.L/.L/1M21M24N54N57O87O8:P;:P;=Q>=Q>@RASCSCTDTDUEUEVFVFWGWG"XH"XH%YI%YI(ZJ(ZJ+[K+[K.\L.\L1]M1]M4^N4^N7_O7_O:`P:`P=aQ=aQ@bRdcedcegfhgfhjikjikmlnmlnpoqpoqsrtsrtvuwvuwyxzyxz|{}|{}~~ cdcdfgfgijijlmlmopoprsrsuvuvxyxy{|{|~~  ccffiilloorruuxx{{~~ ! ! $#$#'&'&*)*)-,-,0/0/323265659898<;<;?>?>BA CCDDEEFF G G#H#H&I&I)J)J,K,K/L/L2M2M5N5N8O8O;P;P>Q>QAR CSCSDTDTEUEUFVFVGWGWHXHXIYIYJZJZK[K[L\L\M]M]N^N^O_O_P`P`QaQaRb                    !!" ##$$%%&&''(())**++,,--..//0 0 1!1!2"dedeghghjkjkmnmnpqpqststvwvwyzyz|}|}           ddggjjmmppssvvyy||        !!" ##$$%%&&''(())**++,,--..// 0 0!1!1"2tests/meshes/ugrid/pyra_cube.ugrid000066400000000000000000000002661456244072500176400ustar00rootroot000000000000009 0 0 0 6 0 0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 1.0 1.0 0.0 0.0 0.0 1.0 1.0 0.0 1.0 0.0 1.0 1.0 1.0 1.0 1.0 0.5 0.5 0.5 2 1 9 4 3 6 8 9 5 7 6 2 9 8 4 5 1 9 6 2 3 1 9 7 5 7 8 9 3 4 tests/meshes/ugrid/sphere_mixed.1.lb8.ugrid000066400000000000000000011354541456244072500211770ustar00rootroot00000000000000 `p# @ Nn0WL?Y4տ޺9YS|?pEaaٿʓ?LXzۿuy޿S&`.+' #07 ۿv~d#9u?nV"޿~<@D? 9uoV"޿Ul#7 ?Ij FĿl\( oݿl%?-7ϿX _ۿuy?V&`¿خɊ#07 ?}ź ˿uz4g#. ~/'?eѿAgvjmȽ?Fױпu6]Ϳɽ?\^\6տ+IDk? ؿ{H+=DOV?nӿiD܊ԿF^?Ei׿aX˿DOV?H_&ۿPpE릇cx?paQ[ݿ{QqگSl#7 ?&uԿH4n׿|<@D?|ؿË\Hҿ|<@D?٣ B<ܿaՠȿSl#7 ?KZ޿ l%?27߿tuy?[&`.+' ?#07 ?ź ˿cz4g#.?~/'?e7?ɽ?_^\6տo+?Ƚ?Kױпu6]?HDk? ȿy:mV?DOV?H_&ۿ/pE?G^?Ii׿QX?DOV?nӿiD܊?ꦇcx?paQ[Ϳ,^tl?Ul#7 ?KZ޿ ?<@D?ݣ B<ܿQՠ?~<@D?|ؿ\H?Tl#7 ?&uԿH4n?l%??7ϿT _?#07 ?CMskz4g#.?ʽ?jhܰ5p9?ʽ?Fhܰ?6p9?DOV?2}k2~ǎ?G^?NAGZX?EOV?}k2~?ʎ?Tl#7 ?Ij FĿi\( o?}<@D?a9umV"?}<@D?8u?oV"?Xl#7 ?Ij F?m\( o?%- |ӆ,t/no?G[&?mķ޿X 1?lށ0?k3<߿kK?EE/}[?߿N:?l ?vm0ge~䌻ӳ?*H+?9ujDæ?u yv?P}⿅ǻ?\? 9i俕?//ɂ?&+7ܗd?_BQ?ݽa[wl1?: ?ᅨ4=0.?YntY?c`xI&R?"2?(׼ |'?,3:-?xyO&`?.+' ?N޿>o?="[ ,F?QJ翟wd?$*_@?[cX [?P?bR?OEU?0g8N?R?~/'e?7?-C ܿUkJ%?K#+I?/$4ܿMA?#;mx?Aվܿ!s ?cJE@̿?P&fݿ%b?ɡ/?1ݿN?a/޲?ҰǷȁ߿Mjغq?}G? &Ὶ}l?6B"?ke #`4?V]V?IL}.\{hw?ȵ?onEܷۛ?B?쿠Qo?Y]n +%?q,)rO?ֶ ? -1?tx?#07 ~ź ?uz4g#.?:@ڿm.w?p<@ڿi|??!<.P@+ۿ?Fl<Յ èۿig?{wp<Ukܿ~tT?\ik֝<[qZ ޿OB_u?yBl<@ YD?lG&<9b?f/ʢ<81$KuY?r]Mg !eC?@3տa ? &?Ul),տY`?"L?b!׿?./?ٿd<=?ZWc0?O/ۿGf ?s?r߅޿X٬?_1V,?V ;IN?c?J%e2?6쨊?w+D}JUŜ?I ??a>pU?@ʮ?KDk ?:mV?mfɆ̴ֿn?t1ɫv?FOD׿LwW(?m?P+W>׿/U?h ?=ܺ:׿=p?bt|?L~fؿ12?go?h#aٿ]PK0L*?F{?a,&ۿw?oN{?G޿RV?v?@F;|O?_ ؼ+B?Voa㿶 Mq?8[? +*?F4{h?ٳBt/h?>pK}?H-@la?4 ?̽Gױ?u6]?mfɆֿwII? ;?GOD׿g Пi?/̽?P+W>׿wy?{R3?>ܺ:׿fj?fG?M~fؿPEv ?a˚?h#aٿW ?OqU?b,&ۿ ?I0eq5?G޿;??@F=-[?2u`?VoaWˈF?-v? +CB?F3?ٳ+bS??qө?H- 7?XuY2+?̽`^\6?+?J}Կi?9h\ڡpU?vtڂ?N@>?j[UEä ?`+?N迗y7;?Ġtg?FOVH_&?NpE?!xɿ 5t?>BK幢<)Jɿ"?~ˡW֢<4qɿ/?89Z<qʿjj(|z?f G`<6G\D˿qǢm?J<.ma̿?CÜ <&HjCϿ.R?JEb<+ѿ?P#*_<nB ?U0K<驪cx鿊paQ[?8=<ǧ8Nm? ̡w?P!Hh4?hr[?iNTӢ'(??83@~h?Yѭk?ȷ3W4̈́?n oiN?.z(B??u>)x\ZL+Bf?ە?rếgkO?St?=jn9ր0?|{4?n-ʿf'] ??Q1οt?o?I-?LѿZL? ^:?us儾տF@^)w?9?~<@Dῶ|?ŋ\H?i8SaT??̀?\m_??#Λ p?程=*?zS'BOruP?gb4_~?xG*|¿aR:?^(j? (wÿ`ĵw?b1?f1ſo%T?r I?ؔHǿ` ?p-@Ң?4@¹>-ʿ#g?v6_x?Q1οk9?J?Lѿg=?rLg?us儾տ'Z?axF?ۿ`(?Ý]?~<@Dݣ BR?np¿ay;?̨9z?+MAĿ݅l?̣0?Ecƿc"?xr$4?mv]Eʿ3G?ݨ?$ao@Ͽ^o튛? *?1 < }ҿ>7?JVE>?{2׿b)V?&6?Zl#7 ޿KZ? ?ʧ8Tm?Y^)xaZL+Bf?fVbSЧ<=jn9ր0?t۠>ƪ<n?&g|<? ?$,?<5Ғ?B.GE?\<ͪiA?ӄ?|<:{T?:?)Oы<̼2Ց?v^?{%tw?5m ?ѻF?2۬UJ[<`+0?^ g?Dʒ[<p?ugK?j: +\g0WL?Y4?¢7){S?$ei  ?E0W< ??)-Z?ܰp?~$fPr[!-i? ?#N]4ٟ?^p? |i`sWl*xu?5a?Ltb6??,վHeڿD?C?a5iDxVm?^,Ga?Y-n?6<U?,s^h?$X?t`XxlBX?^NmLN?㛡>fwQ? Ͱ?e4]wd(?SʭB.?Kwڭ:-?w?\6x^w?nb?hxfW?J?frKzg1AR?Q;ւ?v|U^fx?:9?2ClrUzjYc?5cˉ?4GϭVK ?apc?A#d*1ļ?PԍH?W,'+(_m?8٭W?)^ӏ?w?[oeM5]?4+I? ڝИR_Õ?"?!aNm%- ?SXY:<1!rKlB&?0S'S]s񺄼VQ!? )1}P<=6ԅ"ei  ?;<Hć?&,c`ڣo?G[&mķ޿` 1?iށ0k3<߿sK?BE/}[߿N:?l vm0ge࿇䌻ӳ?*H+9ujD!æ?r yv¿P}⿐ǻ?\ÿ 9i俢?+/ɂſ&+7d?ZBQȿݽi[wl1?: ̿ᅰ4=0.?VntYпc`xI2R?"2Կ)׼ Ν|'?(3:-ٿyyX&`?.+' -C ܿXkJ%?J#+I.$4ܿMA?;mxAվܿ$s ?cJE@̿O&fݿ(b?ɡ/1ݿQ?[/޲ѰǷȁ߿Mjغq?vG &῜}l?.B"ÿke #`4?M]VſHL}._{hw?ȵǿonHܷۛ?B˿쿣Qo?S]n +%пp,*rO?ֶ ӿ •-1?txؿ#07 ź ?jz4g#.߿:@ڿp.w?܁ο@ڿi|?%dο.P@+ۿ?,OϿՅ èۿig?B+#ϿUkܿtT?{ooп[qZ ޿SB_u?5UNѿ@ YD?rҿ9b?/$Կ81*KuY?;,F׿QJ翭wd?!*_@ڿ[cX [?P߿bR?OEU0g8N?P~/'e?7mfɆֿwII? ;FOD׿h Пi?̽P+W>׿wy?jR3=ܺ:׿fj?|fGL~fؿPEv ?a˚h#aٿW ?FqUa,&ۿ ??0eq5¿G޿;?ÿ@F=-[?2u`ƿVoaXˈF?-vɿ +CB?63οٳ,bS??qөҿH- 7?LuY2+׿̽`^\6?x+ݿmfɆֿ"̴n?o1ɫvͿGOD׿LwW(?mͿP+W>׿/U?c Ϳ>ܺ:׿=p?bt|οM~fؿ 12?boϿh#aٿbPK0L*?}F{пb,&ۿw?lN{ҿG޿WV?sӿ@FA|O?\ ؼ+BֿVoa㿽 Mq?8[ٿ +*?A4{h޿ٳGt/h?;pK}H-Fla?4 ̽Kױ?u6]J}Կi?0pU?@ʮKDk ?|:mVCGqϿ=`Bs%?z^r])Ͽ3~N? Ħs;IϿxX?tϻV5Dпؠ+?tm5P&?N@>̿j[UEä ?T+ѿN还y7;?tgտGOVH_&?;pEۿ_пT~?gNup˿пq?VK˿k:пWp'?L=˿@ѿo硖?.\jd̿l&%ѿakZ?FͿ:ҿ0?(c"οWĂeԿRnp¿ay;?9z+MAĿޅl?̣0Fcƿc"?lr$4¿ov]Eʿ4G?ݨĿ&ao@Ͽ^o튛?*ȿ2 < }ҿ>7?JVE>ο{2׿c)V?&6ҿ[l#7 ޿KZ? ؿi8SaT? ?̀ȿ\m_?ȿ#Λ p?ܨ=*ɿzS'COruP?\b4_~ɿyG*|¿aR:?S(jʿ (wÿaĵw?b1˿f1ſo%T?r IοܔHǿ` ?i-@Ңп8@¹>-ʿ#g?o6_xҿQ1οl9?JտLѿg=?rLgٿys儾տ'Z?axF߿ۿ`(?Ý]㿁<@Dޣ B-ʿi'] ?ۿQ1οt?o?B-߿Lѿ^L? ^:ys儾տJ@^)w?~9쿁<@DῺ|?\HL0D&flft?E1xf׿YTqY*?R׿[ӕŨw?2׿"^$2Ab=? : GSؿ@o Q?a eWٿ$F)#\=?=jڿnp¿@;?ȽRܿ+MAĿ9j@?LE}߿Fcƿ+[A?Rvov]Eʿ(5`?Rgr,|&ao@Ͽs30?PXߤC2 < }ҿ6ǥ+?{2׿ k?\'Zc[l#7 ޿&u?H4nʧ8Xm? ̡wۿS!Hh4?hr[ۿlNTآ'(?ۿ;3@~h?Yѭk̷ܿ3W4̈́?i oiNݿ.z(B?޿u>)xdZL+Bf?ڕrếokO?St⿉=jn9ր0?y{4俘n-=?Iſ?Q)Ix>?ҰpſR!-i? ƿty%UT4ٟ?^pȿVz UVtWl*xu?5a˿LyY7?οƙ>>\ڿD?;ѿ?pϞ'aDxVm?U,GaտB`LSd?+<Uٿoi.j_h?$X߿pmBX?UNmLN2?'-rn?#- п_ RrY?KlB&п럎sC?EG"Qп\d[s9@?'_пs?SQ!ѿ>OuW>?ei  ҿsJXv ?ӿ #yB.GE?5ҒտNe3 D|ӄ?ΪiAؿ]M:?<{Tۿc2Nv^?ͼ2ՑN2`z'+s?F .&\CB}п?(LXz?|=> ?ѻFտqb+0?^ gտ€ۆp?ugKտڅD|ZF?_`ֿ$"nU)13eJt?;twٿ])˳gdЕ?B1Lٿ8 ?'JPٿ,><;?TrYڿ)u~5?6,ۿQ-Ͼ?~A8<ܿΣ`w'[?%t'߿%0왼 ^F?$%烝v?GJ=㿪ϠTb ?0濒_裼w.? Hl-  6?v3uP=-:8͖?^a޺9[S|?pEaag缑(- ?kۿmבKlB&?Yۿ!18KG"Q?CܿLBQZǹ'_?6@ܿlz쒼YQ!?ݿ9W%ei  ?W>߿o@沕? #C ֗5Ғ?@.GE⿶̚תiA?Є忆J鞼F{T?:[NҼ2Ց?r^"(CM .&?'+sMn(?B}пʓ?LXzN޿>oG[&mķ޿^ 1lށ0k3<߿qK㲿EE/}[߿N:l vm0ge࿄䌻ӳ*H+9ujDæᴿu yv¿P}⿍ǻ\ÿ 9i俞//ɂſ&+7d_BQȿݽg[wl1: ̿ᅭ4=0.ÿYntYпc`xI.Rǿ"2Կ(׼ ȝ|'Ϳ,3:-ٿxyT&`ҿ.+' -C ܿtQ5,F׿QJ翢wdο$*_@ڿ[cX [ҿP߿bRֿOEU0g8NۿR~/'e7mfɆֿCl?0[#ֿGOD׿JL~ ?&żDֿP+W>׿4IKP2?nֿ>ܺ:׿ `?(0ֿM~fؿLk ?o㇞׿h#aٿ=.?#4ؿb,&ۿWQ?檆ۿG޿܊?kmݿ@Fwk?QAC࿞Voaޣ*o|?ҧ4J +翓#dv?0Dٳ쿢{?׿%IKP2nֿ>ܺ:׿`(0ֿM~fؿLk p㇞׿h#aٿ-.$4ؿb,&ۿWQ檆ۿG޿܊kmݿ@FwkQAC࿞Voaţ*o|ҧ4J +翄#dv0Dٳ쿐{?<ſ)H-Uewʿ찖P̽Qhп8p9J}Կiȿ2pU㿒@ʮKDk :mVDGqϿ]=zJ? ',ڿ*ϿºǾ?Zۿt;IϿ?_ۿV5DпX5{?rۿ&!Q8Z-ʿtд?oK16Q1οSYS?";Lѿ,=:p? N={s儾տ.yyJ?uZGۿe(?9<@D@9u?pV"i8S\| Pxî޿\m2((g[޿#Λ .- j:߿zS'GlQ߿{G*|¿e/ &d (wÿOCf1ſmڰuߚ ޔHǿPu[c:@¹>-ʿOдoK16Q1οSYS#;Lѿ=:p N=zs儾տ.yyJvZGۿe(ſ9<@D9u˿rV"L0D&ۅ!0ĿZݿYTXcOĿ0Llݿ[ӕ^OĿK޿"^$2`.Ŀ w޿ŊſEӿ߿$F-Nqǯƿ$np¿ ȿްl⿝+MAĿJ%!˿Fcƿ7K ο`Oov]Eʿ}̗ѿݩ&ao@ϿgXFԿ\Q{2 < }ҿEmWٿ%3c򿃜{2׿f߿֑[l#7 ޿Ij Fo\( oɧ8OmϿ ̡wۿR!Hh4Ͽhr[ۿkNTӢ'(пۿ:3@~hпYѭkܿ˷3W4̈́пm oiNݿ.z(Bѿ޿u>)x\ZL+BfӿەrếgkOտSt⿈=jn9ր0׿{{4俘nbM>^xNW4?5E#-2â>@X?i fW?UP? jcCKcn?2<𿦢NL] ?k]| cWB 8?KîjDHh&…?[E} @K<<%- Aᥙof#YD?h<"ei  +EIH|,< 2Csy޲<5Ғ›nk^6<ҪiA迂ǽ:dyw<@{T뿮 xY :.m<ϼ2Ց'B=]x>~_iNW45E#L-G>@Xÿi"eO>UPƿ jClإKcnʿ2< }ɜԥN пm]|KR5 8ԿMîjvTUHh&…ٿ[#0j;kȿstݿwF/ָȿI!ݿMȿS'zS'޿T`\hɿli޿S ‼&M3ʿBTI߿ȁVH˿*x Gv\x0 ο$%9KD8CwпtNRA釼2 ҿATiz1C]eտZ鿪ÂUODXٿLn,.ݓV޿ד&ħ+˜347c4cFYb3yʴd;"k"- пnۿ''KlB&пYۿJ1NDG"QпCܿ߿Z k]ӿ 0ׄ1p5ҒտB.GEC@ َͪiAؿӄr(mʑ:{Tۿ:+]̼2Ցv^ZmF .&俽'+s0🼛(B}пP ~Y○LXzN޿>o¿)U,_mķ޿a 1¿Ղk3<߿tK¿&3߿N:ÿvm0ge࿈䌻ÿj;z͆9ujD"æĿR۠P}⿑ǻƿc%$ 9i俢ȿ+9!&+7d̿E=%ݽi[wl1пHxEXᅰ4=0.ӿO[c`xI2R׿_ζҚ(׼ Ν|'ݿxqUxyX&`⿚o3L-C ܿXkJ%˿K#+I.$4ܿMA˿";mxAվܿ$s ˿cJE@̿O&fݿ(b̿ɡ/1ݿQ̿`/޲ѰǷȁ߿Mjغqο|G &῜}lп5B"ÿke #`4ҿT]VſHL}._{hwԿȵǿonHܷۛ׿B˿쿣QoۿX]n +%пp,*rOΎֶ ӿ •-1忥txؿ#07 ź tz4g#.߿9@ڿn.wѿ܏@ڿi|ѿ隼-P@+ۿҿ 3 1Յ èۿigҿZUkܿtTҿ[qZ ޿PB_uӿ`@ YDտ,g ,]9b׿M 81'KuYڿ6/6QJ翪wd޿>m O[cX [j7ޜbR8nɰ0g8Nӻ촼~/'eF֩mfɆ̴ֿnѿt1ɫvͿFOD׿LwW(ѿmͿP+W>׿/Uѿh Ϳ=ܺ:׿=pѿbt|οL~fؿ12ҿgoϿh#aٿ^PK0L*ӿF{пa,&ۿwԿoN{ҿG޿SVֿvӿ@F<|Oٿ_ ؼ+BֿVoa㿸 Mqݿ8[ٿ +*F4{h޿ٳCt/h>pK}H-Ala꿘4 ̽Hױ𿴆u6]mfɆֿwIIտ ;FOD׿g Пiտ/̽P+W>׿wyտ{R3=ܺ:׿fjֿfGL~fؿPEv ֿa˚h#aٿW ׿OqUa,&ۿ ڿI0eq5¿G޿;ܿÿ@F=-[2u`ƿVoaWˈF⿟-vɿ +CBF3οٳ+bS?꿾qөҿH- 7XuY2+׿̽`^\6+ݿJ}Կiؿ(mW Կ7pQؿrȏx0ۡ[ԿUgjٿϧ@3տa ٿmhA=Ul),տY`ڿja&b!׿ۿ}$Sٿl<=޿FBਬO/ۿKf G={r߅޿X٬EﲱV ;IN忒= jJ%j24-.w+D}PUŜYjg?a>pU+9S¼KDk ;P[YǼCGqϿУrӿ-돣Կ)ϿGPӿU$k5Կs;IϿ6#ӿ!kԿV5Dп,ԿJeԿ&N@>̿j[UEä a+ѿN迗y7;ŠtgտFOVH_&PpEۿ!xɿ 5tݿ PW)Jɿ"ݿpWlh2qɿ/ݿ[9 viqʿjj(|z޿g`쬼6G\D˿qǢm߿ xӭ,ma̿LYs&i&HjCϿ.R297/+ѿhDRȲuNӿm @d3Py1vDֿij-/&C[\H`ڿɜn!f'cnڼVu 6 ^|]y8܊nB @+hżcx鿊paQ[쒇/˼L0D&blftԿH1xf׿YTmY*ԿU׿[ӕŨwԿ2׿ ^$2Ab=տ$: GSؿ;o Qտe eWٿ$F##\=׿Ajڿnp¿:;ٿȽRܿ+MAĿ9j@ۿQE}߿Ecƿ+[A߿Uvmv]Eʿ$5`Ugr,|$ao@Ͽn30TXߤC1 < }ҿ0ǥ+鿚{2׿k\'ZcZl#7 ޿&uH4ni8S%ؿ0/]nXҿ\mNٿ榤Ltҿ#ΛUJKٿgAKҿzS'Kd3$ٿwR"nҿyG*|¿jڿ3Fݒӿ (wÿj.ۿݚԿf1ſIq޿'qֿܔHǿKS9 ؿ8@¹>-ʿf'] ⿥ۿQ1οt?oJ-߿LѿZL鿸 ^:ys儾տF@^)w9쿁<@Dῶ|Ƌ\Hi8SaTܿ?̀ȿ\m_ܿȿ#Λ pܿ訋=*ɿzS'AOruPݿhb4_~ɿyG*|¿aR:޿_(jʿ (wÿ_ĵw߿b1˿f1ſo%Tr IοܔHǿ_ p-@Ңп8@¹>-ʿ#gv6_xҿQ1οi9JտLѿg=rLgٿys儾տ'ZaxF߿ۿ`(Ý]㿁<@Dۣ BRnp¿ay;Ѩ9z+MAĿ݅ḷ0Ccƿc"|r$4¿kv]Eʿ3GݨĿ"ao@Ͽ^o튛*ȿ0 < }ҿ>7JVE>ο{2׿b)V&6ҿWl#7 ޿KZ ؿŧ8Tm߿Q_䭼N!Hh4߿X׌ggNT֢'(2->b63@~hw0Ʒ3W4̈́Ph-_导.z(BΈ˰u>)xbZL+BfQjHrếmkO4(=jn9ր0翔iӃntwٿ τdЕӿE1Lٿ5i0ӿ'JPٿ n_RUh:<;ԿTrYڿu~5Կ6,ۿQJP]?ϾտA8<ܿZ9E:OV׿%t'߿25j͋ ^Fڿ7ēB⃝vݿIJ=>&Qb ῒ0$.lZw. H=P~x31Ѝ.:8͖`aZV_WS|pEaa^y":> ؿѻFտ`|CB_+0ؿ^ gտY${pؿugKտ-nU`ޅyZFؿ_`ֿ2v֌%13<ٿOޜfֿ|&6ۿi*׿l ډ_%jݿE+bڿ]fՃ?(xPIܿtKp+*^#= yjMJ@#KC DpQЕ,bi4_Q.bo Gih󇠼  V98eT<0WLY4O弁kۿ(- п,5ׁYۿKlB&п,6CܿKG"Qп"GgZ6@ܿǹ'_п:삼ݿYQ!ѿ%UW>߿%ei  ҿ 㲅 ῿ӿև@.GE⿞5Ғտ*̊ЄתiAؿ{鎼:F{TۿyNr^Ҽ2Ց&C'+sM .&uQhkB}п(d򑭡LXzM xؕE s޿[I_Ŀex3M޿zB~Ŀ=Lx}޿^DĿjN cy;-=߿Iſ\=-z(Ix>ްpſjM{!-i ƿg~4ٟ^pȿ^JE|rWl*xu5a˿xr 5翪οv]a ڿDFѿȰuFRDxVma,Gaտ +ZCˎ:<UٿiY30\h$X߿siBX`NmLNp7:Q߿ Ͱ/)ִ:d(ZʭB.簿yO:ڭ:-w`_"dx;^wnbS<fWJrIV=g1ARZ;ւᲿQ=@U^fxC9+VbAUzjYc5cˉzռyDVK apcm."G*1ļPԍHQfK+(_m8٭WF Pӏwſ:)ZT5]4+Iʿ<-uZ_Õ"пyx,|<%- t*ܷ2[d|f_`<ҪiA8^;c<@{T̬_%q&~k{<ϼ2Ցy"soG[&?mķ޿g 1jށ0?k3<߿zK㲿CE/}[?߿N:l ?vm0ge࿎䌻ӳ*H+?9ujD(æᴿs yv?P}⿘ǻ\? 9i俪,/ɂ?&+7d[BQ?ݽn[wl1: ?ᅴ4=0.ÿVntY?c`xI:Rǿ"2?(׼ ם|'Ϳ(3:-?xy^&`ҿ.+' ?-C ܿ\kJ%˿J#+I?.$4ܿMA˿;mx?Aվܿ(s ˿cJE@̿?O&fݿ,b̿ɡ/?1ݿU̿[/޲?ѰǷȁ߿MjغqοvG? &῞}lп.B"?ke #`4ҿM]V?HL}.a{hwԿȵ?onJܷۛ׿B?쿦QoۿS]n +%?p,,rOῥֶ ? ŕ-1忞tx?#07 ź jz4g#.?9@ڿt.w܁?@ڿi|%d?-P@+ۿ¿,O?Յ èۿig¿B+#?UkܿtT¿{oo?[qZ ޿WB_uÿ5UN?@ YDſr?9bǿ/$?81/KuYʿ;,F?QJ翳wdο!*_@?[cX [ҿP?b RֿOEU?0g8NۿP?~/'e7?mfɆֿwIIտ ;?EOD׿i Пiտ̽?P+W>׿wyտgR3?<ܺ:׿fjֿyfG?K~fؿPEv ֿa˚?h#aٿW ׿DqU?a,&ۿ ڿ=0eq5?G޿;ܿ?@F=-[࿾2u`?VoaYˈF⿏-v? +CB33?ٳ.bS?꿳qө?G- 7KuY2+?˽b^\6w+?mfɆֿ#̴nѿl1ɫv?EOD׿LwW(ѿm?P+W>׿/Uѿ` ?<ܺ:׿ =pѿ bt|?K~fؿ 12ҿ^o?h#aٿcPK0L*ӿ{F{?a,&ۿwԿjN{?G޿XVֿp?@FB|OٿX ؼ+B?Voa㿾 Mqݿ8[? +*=4{h?ٳHt/h8pK}?G-Gla꿐4 ?˽Lױ𿪆u6]?J}Կ%iȿ/pU㿏@ʮ?JDk {:mV?BGqϿ=`Bs%ۿt^r]?(Ͽ3~Nۿ Ħ?r;IϿxXۿtϻ?V5Dпؠ+ܿnm5P?&N@>?j[UEä P+?N还y7;tg?FOVH_&5pE?_пT~׿dNup?пq׿VK?k:пWp'ؿ L=?@ѿp硖ؿ*\jd?l&%ѿbkZٿF?:ҿ0ڿ$c"?VĂeԿR?np¿ay;⿯9z?+MAĿޅḷ0?Ecƿc"fr$4?mv]Eʿ5Gݨ?$ao@Ͽ^o튛*?1 < }ҿ>7JVE>?{2׿d)V&6?Zl#7 ޿KZ ?i8SaTܿ ?̀?\m_ܿ~?#Λ pܿ٨=*?zS'EOruPݿYb4_~?zG*|¿aR:޿P(j? (wÿcĵw߿b1?f1ſo%Tr I?ܔHǿa g-@Ң?8@¹>-ʿ#gl6_x?Q1οm9J?Lѿ g=rLg?ys儾տ'ZaxF?ۿ`(Ý]?<@D B-ʿj'] ⿜?Q1οt?o@-?Lѿ`L鿲 ^:?ys儾տM@<y[?ۿP>^)w|9?<@D´|\H?L0D&ilftԿC1xf?YTtY*ԿP?[ӕŨwԿ2?^$2Ab=տ: GS?Co Qտ_ eW?$F,#\=׿;j?np¿C;ٿȽR?+MAĿ9j@ۿIE}?Bcƿ+[A߿Pv?jv]Eʿ*5`Ogr,|? ao@Ͽv30MXߤC?. < }ҿ:ǥ+鿒?~{2׿ k\'Zc?Ul#7 ޿&uH4n?ç8amϿ̡w?L!Hh4Ͽhr[?eNTܢ'(п?43@~hпYѭk?ķ3W4̈́пg oiN?.z(Bѿ?u>)xiZL+Bfӿڕ?rếukOտSt?=jn9ր0׿x{4?n-=߿I?OMS)Ix>̰p?͂|LST!-i ?`9mU4ٟ⿫^p?R7XtWl*xu5a?g[7翏?@ Ƃ'_ڿD6?.>osbDxVmO,Ga?!6;of$<U? k_h$X?` qmBXONmLN?3P3߿ei  ?IA8< ῴ?!_:N ؿѻF?G2i=&pd+0ؿ^ g?-wQppؿtgK?_ 7~p~ZFؿ_`?V~c!q+13<ٿIޜf?B6s r-6ۿi*?Isf%jݿ>+b?aA˒uك?(pPI?*AxKp+*Y#=?U6K{RJ@#EC ?ۯgБ1bi4?ʰ(&Q.bo ?,7   Q98?\B0WLY4? >|<"tӿ8tw?(x}?hag{<ӿ ?/@~<5Ғտ?.GE?У\j)*<ܪiAؿτ?gK̃׿AIKP2n?>ܺ:׿.`(0?M~fؿLk o㇞?h#aٿM.#4?b,&ۿ$WQ檆?G޿Ƞ܊km?@FwkQAC?Voa*o|ҧ4J? +翡#dv0D?ٳ쿳{?<ſ)?H-񿀬ewʿ찖P?̽lhп7p9?mfɆֿCl?1[#?GOD׿2L~ ?&żD?P+W>׿IKP2?n?>ܺ:׿`?(0?M~fؿLk ?p㇞?h#aٿ#.?$4?b,&ۿWQ?檆?G޿܊?km?@Fwk?QAC?Voa㿶*o|?ҧ4J? +|#dv?0D?ٳ쿆{?=zJ?',?)ϿxºǾ?Z?s;IϿu?_?V5DпX5{?r?&-ʿдoK16?Q1οSYS";?LѿR=:p N=?ts儾տ.yyJuZG?ۿe(ſ9?~<@Df9u˿pV"?i8S<|? Pxî?\m(?)g[?#Λy .?- j:?zS'pGl?Q?xG*|¿e?/ &d? (wÿjO?C?f1ſmڰ?vߚ ?ؔHǿ;u[c??4@¹>-ʿ8д?oK16?Q1οxSYS?$;?Lѿ=:p?N=?us儾տ.yyJ?wZG?ۿe(?9?~<@D8u?sV"?L0D&Յ!0?Z?YTXcO?1Ll?[ӕ^O?K?^$2Y.? w?Ŋ?Fӿ?$F-Nqǯ?$?np¿ ?ްl?+MAĿB%!??Ccƿ7K ?`O?kv]Eʿ}̗?ݩ?"ao@Ͽ`XF?\Q{?0 < }ҿ=mW?%3c?{2׿\?֑?Wl#7 ޿Ij F?o\( o?+s<;kȿot?Ȅ4YOtTI?Z/|tv1~<@ ҿ=Ti?i< C]eտZ?{yn08?;h~@Xÿi?귃<?UPƿ j?w.[<Kcnʿ2?20˃<]NW4?5E#?A<>@X?i?+<>UP? j?Wfh<ƥKcn?2o?G[&?mķ?Y 1?jށ0?l3o?>͒Gd9ujD?æ?YtreP}?ǻ?>g 9i??ASœi&+7?d?etC˝mݽ?f[wl1?p?4=0.?7^sc`xI?-R?_]9$x(׼ ?ǝ|'?$:~xy?T&`?H+:@?g.w?݁?@?i|?&d?.P@+? ?-O?Յ è?ig?B+#?Uk?xtT?|oo?[qZ ?IB_u?6UN?@ Y?D?r??9b?0$?81?KuY?<,F?QJ?wd?"*_@?[cX? [?P?b?R?OEU?2g8?N?Q?~/'?e?7?-C ?UkJ%?J#+I?.$4?MA?;mx?Aվ?!s ?cJE@̿?O&f?%b?ɡ/?1?N?^/޲?ѰǷȁ?Mjغq?zG? &?}l?3B"?ke ?#`4?R]V?HL}.?\{hw?ȵ?on?Eܷۛ?B??Qo?V]n +%?p,?)rO?ֶ ? ?-1?tx?#07 ?~ź ?pz4g#.?:@?m.w?BWy<@?i|?d<.P@+??1]J<Յ è?ig?ó5V<Uk?~tT?e_f<[qZ ?OB_u?@r><@ Y?D?<3Ԋ<?9b?x<81?$KuY?K\1pU?@ʮ?KDk? ?:mV?mfɆ? ̴n?t1ɫv?GOD?LwW(?m?P+W>?/U?h ?>ܺ:?=p?bt|?M~f? 12?go?h#a?_PK0L*?F{?b,&?w?oN{?G?TV?v?@F?>|O?_ ؼ+B?Voa? Mq?8[? +?*?E4{h?ٳ?Dt/h?=pK}?H-?Bla?4 ?̽?Iױ?u6]?mfɆ?wII? ;?GOD?g Пi?,̽?P+W>?wy?xR3?>ܺ:?fj?fG?M~f?PEv ?a˚?h#a?W ?NqU?b,&? ?H0eq5?G?;??@F?=-[?2u`?Voa?WˈF?-v? +?CB?E3?ٳ?+bS??qө?H-? 7?XuY2+?̽?`^\6?+?J}?i?'AS><?l<=?hypU?Õ}?N@>?j[U?Eä ?]+?N?y7;?tg?FOV?H_&?JpE?!x? 5t?Pǣ<)J?"?uН<3q?/?q<q?jj(|z?K <6G\D?qǢm?ö ˟<-ma??9ZF<&HjC?.R?u1 !<+??;4)x?\ZL+Bf?ە?r?gkO?St?=jn9?ր0?|{4?n-?f'] ??Q1?t?o?I-?L?ZL? ^:?vs儾?F@^)w?9?<@D?|?ŋ\H?i8S?aT??̀?\m?_??#Λ? p?樋=*?zS'?BOruP?fb4_~?xG*|?aR:?](j? (w?`ĵw?b1?f1?o%T?r I?ؔH?` ?o-@Ң?4@¹>-?#g?u6_x?Q1?k9?J?L?g=?rLg?us儾?'Z?axF??`(?Ý]?~<@D?ݣ BR?np?ay;?ʨ9z?+MA?݅l?̣0?Dc?c"?wr$4?lv]E?3G?ݨ?#ao@?^o튛? *?0 < }?>7?JVE>?{2?b)V?&6?Xl#7 ?KZ? ?ǧ8?Tm?8D)x?bZL+Bf?b <s?;^?"o?G[&mķ?a 1?lށ0k3?wy?lR3=ܺ:?fj?~fGL~f?PEv ?a˚h#a?W ?GqUa,&? ?@0eq5¿G?;?ÿ@F?=-[?2u`ƿVoa?XˈF?-vɿ +?CB?73οٳ?,bS??qөҿH-? 7?NuY2+׿̽?`^\6?{+ݿmfɆ?"̴n?o1ɫvͿGOD?LwW(?mͿP+W>?/U?c Ϳ>ܺ:?=p?bt|οM~f? 12?boϿh#a?bPK0L*?}F{пb,&?w?lN{ҿG?WV?sӿ@F?A|O?\ ؼ+BֿVoa? Mq?8[ٿ +?*?A4{h޿ٳ?Gt/h?;pK}H-?Fla?4 ̽?Kױ?u6]J}?i?0pU?@ʮKDk? ?|:mVBGq?<`Bs%?{^r](?2~N? Ħr;I?xX?tϻV5D?ؠ+?um5P&?N@>̿j[U?Eä ?U+ѿN?y7;?tgտGOV?H_&?<pEۿ_?T~?hNup˿?q?VK˿k:?Wp'?L=˿@?o硖?/\jd̿l&%?akZ?FͿ:?0?)c"οVĂe?;f?\пMng?Ā?Poҿ '1?M?Zt̺Կƭ? ?L9e׿|l5?*ӆ?>Su *RܿqS#?Ս8?Lo28?GkD?-U_vI^?Ji?YXCGq?Уr?)돣Կ)?GP?U$k5Կs;I?6#?!kԿV5D?,?JeԿ&Rnp?ay;?9z+MA?ޅl?̣0Ec?c"?mr$4¿mv]E?4G?ݨĿ$ao@?^o튛?*ȿ1 < }?>7?JVE>ο{2?c)V?&6ҿZl#7 ?KZ? ؿi8S?aT? ?̀ȿ\m?_?ȿ#Λ? p?ݨ=*ɿzS'?COruP?]b4_~ɿxG*|?aR:?T(jʿ (w?aĵw?b1˿f1?o%T?r IοٔH?` ?j-@Ңп5@¹>-?#g?p6_xҿQ1?l9?JտL?g=?rLgٿus儾?'Z?axF߿?`(?Ý]<@D?ޣ B-?i'] ?ۿQ1?t?o?B-߿L?^L? ^:us儾?J@^)w?~9~<@D?|?\HL0D&?glft?E1xf׿YT?rY*?R׿[ӕ?Ũw?2׿^$2?Ab=? : GSؿ?Ao Q?a eWٿ$F?*#\=?=jڿnp?A;?ȽRܿ+MA?9j@?LE}߿Ac?+[A?Rviv]E?)5`?Rgr,|ao@?t30?PXߤC. < }?8ǥ+?~{2? k?\'ZcUl#7 ?&u?H4nç8?Ym? ̡wۿL!Hh?4?hr[ۿeNT?آ'(?ۿ43@?~h?Yѭkܿķ3W?4̈́?k oiNݿ.z?(B?޿u>)x?eZL+Bf?ەr?pkO?St=jn9?ր0?z{4俓noG[&mķ?^ 1mށ0k3?4IKP2?nֿ=ܺ:? `?(0ֿL~f?Lk ?p㇞׿h#a?=.?$4ؿa,&?WQ?檆ۿG?܊?kmݿ@F?wk?QAC࿞Voa?ޣ*o|?ҧ4J +?#dv?0Dٳ?{??%IKP2nֿ<ܺ:?`(0ֿK~f?Lk p㇞׿h#a?-.$4ؿa,&?WQ檆ۿG?܊kmݿ@F?wkQAC࿝Voa?ƣ*o|ӧ4J +?#dv1Dٳ?{?<ſ)G-?Vewʿ찖P˽?Qhп:p9J}?iȿ2pU㿒@ʮKDk? :mVCGq?]=zJ? ',ڿ)?ºǾ?Zۿs;I??_ۿV5D?X5{?rۿ&-?tд?oK16Q1?SYS?#;L?,=:p? N=vs儾?.yyJ?vZG?e(?9<@D?@9u?rV"i8S?]| Pxî޿\m?3()g[޿#Λ? .- j:߿zS'?GlQ߿yG*|?e/ &d (w?OCf1?mڰvߚ ڔH?Qu[c6@¹>-?PдoK16Q1?SYS$;L?=:pN=vs儾?.yyJwZG?e(ſ9<@D?9u˿sV"L0D&?ۅ!0ĿZݿYT?XcOĿ0Llݿ[ӕ?^OĿK޿^$2?`.Ŀ w޿?ŊſEӿ߿$F?-Nqǯƿ$np? ȿްl⿚+MA?J%!˿Cc?7K ο`Okv]E?}̗ѿݩ"ao@?gXFԿ\Q{0 < }?EmWٿ%3c򿀜{2?f߿֑Wl#7 ?Ij Fo\( oŧ8?OmϿ ̡wۿN!Hh?4Ͽhr[ۿgNT?Ӣ'(пۿ63@?~hпYѭkܿƷ3W?4̈́пm oiNݿ.z?(Bѿ޿u>)x?\ZL+Bfӿەr?gkOտSt⿂=jn9?ր0׿{{4俔no¿jmķ?a 1¿- 9k30g8?N~/'?eCgvjmƼmfɆ?̴nѿu1ɫvͿEOD?LwW(ѿmͿP+W>?/Uѿi Ϳ<ܺ:?=pѿbt|οK~f?12ҿhoϿh#a?^PK0L*ӿF{пa,&?wԿoN{ҿG?SVֿvӿ@F?<|Oٿ_ ؼ+BֿVoa? Mqݿ8[ٿ +?*F4{h޿ٳ?Ct/h>pK}G-?Ala꿘4 ˽?Hױ𿴆u6]mfɆ?wIIտ ;FOD?f Пiտ2̽P+W>?wyտ~R3=ܺ:?fjֿfGL~f?PEv ֿa˚h#a?W ׿QqUa,&? ڿK0eq5¿G?;ܿÿ@F?=-[2u`ƿVoa?WˈF⿡-vɿ +?CBI3οٳ?*bS?qөҿH-? 7[uY2+׿̽?^^\6+ݿJ}?iؿyyVW ?7pQؿG򣅁ۡ[?Ugjٿ̉3ͬ@3?a ٿ~-sARUl),?Y`ڿAn5,pU)*ƼKDk? {H+=̼BGq?Уrӿ-돣Կ(?GPӿU$k5Կr;I?6#ӿ!kԿV5D?,ԿJeԿ&N@>̿j[U?Dä c+ѿN?y7;ȠtgտFOV?H_&SpEۿ!x? 5tݿ1H)J?"ݿCҌ2q?/ݿصA;>q?jj(|z޿F&D6G\D?qǢm߿$1L0 ,ma?QȨ&HjC?.Rx ݌+?yuN?m @˲%y1vD?ij&ٻ\H`?ɜn!fB#~Vu 6 ?^|`rļnB? >ɼcx?paQ[ {QqϼL0D&?blftԿH1xf׿YT?mY*ԿU׿[ӕ?ŨwԿ2׿^$2?Ab=տ$: GSؿ?;o Qտe eWٿ$F?##\=׿Ajڿnp?:;ٿȽRܿ+MA?9j@ۿQE}߿Bc?+[A߿Uvjv]E?$5`Ugr,| ao@?n30TXߤC. < }?0ǥ+鿚~{2?k\'ZcUl#7 ?&uH4ni8S?%ؿ0/]nXҿ\m?Nٿ榤Ltҿ#Λ?UJKٿgAKҿzS'?Kd3$ٿwR"nҿwG*|?jڿ3Fݒӿ (w?j.ۿݚԿf1?Iq޿'qֿהH?KS9 ؿ3@¹>-?f'] ⿥ۿQ1?t?oJ-߿L?ZL鿸 ^:ts儾?F@^)w9~<@D?|Ƌ\Hi8S?aTܿ?̀ȿ\m?_ܿȿ#Λ? pܿ騋=*ɿzS'?AOruPݿib4_~ɿwG*|?aR:޿`(jʿ (w?_ĵw߿b1˿f1?o%Tr IοהH?_ q-@Ңп3@¹>-?#gx6_xҿQ1?i9JտL?g=rLgٿts儾?'ZaxF߿?`(Ý]~<@D?ۣ BRnp?ay;Ө9z+MA?݅ḷ0Bc?c"}r$4¿jv]E?3GݨĿ ao@?^o튛*ȿ. < }?>7JVE>ο~{2?b)V&6ҿUl#7 ?KZ ؿƧ8?Tm߿O!Hh?4߿N迯hNT?֢'(࿏K 73@?~he놁2TǷ3W?4̈́ Xvְ.z?(Bp|u>)x?bZL+Bf㿟uNr?mkO_14=jn9?ր0翶طnoG[&?mķ?f 1iށ0?k3?wyտcR3?=ܺ:?fjֿufG?L~f?PEv ֿa˚?h#a?W ׿BqU?a,&? ڿ;0eq5?G?;ܿ?@F?=-[࿻2u`?Voa?YˈF⿋-v? +?CB.3?ٳ?-bS?꿰qө?H-? 7GuY2+?̽?a^\6r+?mfɆ?$̴nѿk1ɫv?EOD?LwW(ѿm?P+W>?/Uѿ_ ?<ܺ:? =pѿ bt|?K~f? 12ҿ]o?h#a?dPK0L*ӿ{F{?a,&?wԿjN{?G?YVֿp?@F?C|OٿX ؼ+B?Voa? Mqݿ8[? +?*<4{h?ٳ?Ht/h8pK}?F-?Gla꿐4 ?ʽ?Lױ𿪆u6]?J}?&iȿ/pU㿏@ʮ?JDk? {:mV?BGq?=`Bs%ۿq^r]?(?3~Nۿ Ħ?r;I?xXۿtϻ?V5D?٠+ܿkm5P?&N@>?j[U?Fä N+?N?y7;tg?GOV?H_&2pE?_?T~׿bNup??q׿VK?k:?Wp'ؿ L=?@?p硖ؿ(\jd?l&%?bkZٿF?:?0ڿ"c"?WĂe?R?np?ay;⿭9z?+MA?ޅḷ0?Cc?c"er$4?kv]E?5Gݨ?"ao@?^o튛*?0 < }?>7JVE>?{2?d)V&6?Wl#7 ?KZ ?i8S?aTܿ?̀?\m?_ܿ}?#Λ? pܿب=*?zS'?EOruPݿXb4_~?zG*|?aR:޿O(j? (w?cĵw߿b1?f1?o%Tr I?ܔH?a g-@Ң?8@¹>-?#gl6_x?Q1?m9J?L? g=rLg?ys儾?'ZaxF??`(Ý]?<@D? B-?j'] ⿜?Q1?t?o@-?L?`L鿲 ^:?ys儾?M@<y[??P>^)w|9?<@D?|\H?L0D&?ilftԿB1xf?YT?tY*ԿO?[ӕ?ŨwԿ2?^$2?Ab=տ: GS??Co Qտ^ eW?$F?,#\=׿:j?np?C;ٿȽR?+MA?9j@ۿHE}?Cc?+[A߿Pv?kv]E?*5`Ogr,|?"ao@?v30MXߤC?0 < }?:ǥ+鿑?{2? k\'Zc?Wl#7 ?&uH4n?ȧ8?amϿ̡w?Q!Hh?4Ͽhr[?jNT?ܢ'(п?93@?~hпYѭk?ʷ3W?4̈́пh oiN?.z?(Bѿ?u>)x?iZL+Bfӿڕ?r?ukOտSt?=jn9?ր0׿y{4?n?AIKP2n?>ܺ:?.`(0?M~f?Lk o㇞?h#a?M.#4?b,&?$WQ檆?G?Ƞ܊km?@F?wkQAC?Voa?*o|ҧ4J? +?#dv0D?ٳ?{?<ſ)?H-?ewʿ찖P?̽?lhп7p9?mfɆ?Cl?1[#?GOD?2L~ ?&żD?P+W>?IKP2?n?>ܺ:?`?(0?M~f?Lk ?p㇞?h#a?#.?$4?b,&?WQ?檆?G?܊?km?@F?wk?QAC?Voa?*o|?ҧ4J? +?|#dv?0D?ٳ?{?=zJ? ',?)?xºǾ?Z?s;I?u?_?V5D?X5{?r?&-?дoK16?Q1?SYS";?L?O=:p N=?us儾?.yyJuZG??e(ſ9?<@D?d9u˿pV"?i8S?<|? Pxî?\m?(?)g[?#Λ?y .?- j:?zS'?pGl?Q?xG*|?e?/ &d? (w?jO?C?f1?mڰ?vߚ ?ؔH?;u[c??4@¹>-?8д?oK16?Q1?xSYS?$;?L?=:p?N=?us儾?.yyJ?wZG??e(?9?~<@D?8u?sV"?L0D&?Յ!0?Z?YT?XcO?1Ll?[ӕ?^O?K?!^$2?Y.? w??Ŋ?Fӿ?$F?-Nqǯ?$?np? ?ްl?+MA?B%!??Fc?7K ?`O?nv]E?}̗?ݩ?%ao@?`XF?\Q{?2 < }?=mW?%3c?{2?\?֑?[l#7 ?Ij F?o\( o?                !!" ! # #$!$%"%&# $! %"!'#'($()%)*&*+'#($#)%$*&%,',-(-.)./*/0+01,'-('.)(/*)0+*2323432"535646753643"&858969:7:;85"965:76&+<8<=9=>:>?;?@<8&=98>:9?;:+1A<AB=BC>CD?DE@EFA<+B=<C>=D?>E@?2G24HGHIHG247JHJKIKLJH4KIH7;MJMNKNOLOPMJ7NKJOLK;@QMQRNRSOSTPTUQM;RNMSONTPO@FVQVWRWXSXYTYZUZ[VQ@WRQXSRYTSZUTG\GI]\]^]\GIL_]_`^`a_]I`^]LPb_bc`cdadeb_Lc`_da`PUfbfgcghdhieijfbPgcbhdciedU[kfklglmhmninojopkfUlgfmhgnihoji\\^qqq\^arqrssrq^sqaetrtusuvv trausrvsejwtwxuxyvyz zwtexutyvuz vjp{w{|x|}y}~z~{wj|xw}yx~zyz,-,.-/.0/10,-./0A1BACBDCEDFEABCDEVFWVXWYXZY[ZVWXYZk[lkmlnmonpoklmno{p|{}|~}~{|}~ .  J<XJ fX. J .Xt<JXf<JJXXftt*8*F8TFbT*8FTp~.~pp~f.~.~~ff  &4& &BbPB^P l^zl&z4B P ^&l&4zppp"40">0L>ZL"0>Lh4vh"v0>LZ4"h"0v0>>LLZ,:,,HZVHdVrd,r:HV,d,:rZHVdrZHHVVddrr  ( 6:D6 RD`R( 6 D(Rn:|n6|DR`:6n6D|DRR`n|nn||($<$$2`(@2N@$tN<(2$@$<N\`j\2xj@xNt`2\2@j@NxNt\jx\\jjxx .<<JJX < Jft.t<JX<.tJ<XJfttft**88FFTTb*8FT      X* * 8  8 F   *   8 T XT b * b p 8 p ~ F * XT 8 * b F 8 p   T b p ~ T  b T p b ~ p bBBP P^ ^l lz z B P ^ l z  F    ~ & F & 4 4 B B P  F & 4  B ^ ~ ^ l & l z 4 z B P & ~ ^ 4 & l B 4 z P B h hv^ vl z   ^ hl ^ vz l  z     P      "    0 P 0 > > L  L Z  Z h " P 0  >   L "  Z  0 > L Z h 0 > 0 L > Z L h Z  v  v v " h  "      , , : "    , h    , :  h     ,  : , v  H v H v H V V d H d .H V H d r r V d f.V r d V .d : r fr r f :      :                  '(('())()**)*++*+,,+,--,- ..-  5C 6D5 DC5  6D 7E6 ED6  7E8F7FE78F9G8GF89G:H9HG9:H;I:IH:;I<J;JI;CQDRCRQCDRESDSRDESFTETSEFTGUFUTFGUHVGVUGHVIWHWVHIW JXI XWI 'Q_(R`Q(`_Q((R`)SaR)a`R))Sa*TbS*baS**Tb+UcT+cbT++Uc,VdU,dcU,,Vd-WeV-edV--We.XfW.feW.D C  C CE D  D DFE E EGFFFHGGGIHHHJ I I IR(Q(Q('QS)R)R)(RT*S*S*)SU+T+T+*TV,U,U,+UW-V-V-,VX .W. W.-W5m{6n|m6|{m66n|7o}n7}|n77o}8p~o8~}o88p~9qp9~p99q:rq:q::r;sr;r;;s<ts<s<C{D|{D{DD|E}|E|EE}F~}F}FF~G~G~GGHHHHIIIIJJJQRRRRSSSSTTTTUUUUVVVVWWWWXXX_````aaaabbbbccccddddeeeefff|6D{D65{D5C{}7E|E76|E6D|~8F}F87}F7E}9G~G98~G8F~:HH:9H9G;II;:I:H<JJ<;J;IDRRDCRCQESSEDSDRFTTFETESGUUGFUFTHVVHGVGUIWWIHWHVJXXJIXIWR``RQ`Q_SaaSRaR`TbbTSbSaUccUTcTbVddVUdUcWeeWVeVdXffXWfWemnnnnooooppppqqqqrrrrssssttt{||||}}}}~~~~n||nm|m{o}}on}n|p~~po~o}qqpp~rrqqssrrttss||{{}}||~~}}~~                    #$$#$%%$%&&%&''&'(('())()**)#1$2#21#$2%3$32$%3&4%43%&4'5&54&'5(6'65'(6)7(76()7*8)87)1?2@1@?12@3A2A@23A4B3BA34B5C4CB45C6D5DC56D7E6ED67E8F7FE7?M@N?NM?@NAO@ON@AOBPAPOABPCQBQPBCQDRCRQCDRESDSRDESFTETSEM[N\M\[MN\O]N]\NO]P^O^]OP^Q_P_^PQ_R`Q`_QR`SaRa`RSaTbSbaS$###%$$$&%%%'&&&(''')(((*)))2111322243335444655576668777@???A@@@BAAACBBBDCCCEDDDFEEENMMMONNNPOOOQPPPRQQQSRRRTSSSijjijkkjkllklmmlmnnmnoonoppo'w(x'xw'(x)y(yx()y*z)zy)*z+{*{z*+{,|+|{+,|-},}|,-}.~-~}-iwjxwjwjjxkyxkxkkylzylyllzm{zmzmm{n|{n{nn|o}|o|oo}p~}p}pxjwjwjiwykxkxkjxzlylylky{mzmzmlz|n{n{nm{}o|o|on|~p}p}po}'_(`_(_((`)a`)`))a*ba*a**b+cb+b++c,dc,c,,d-ed-d--e.fe.e.wxxxxyyyyzzzz{{{{||||}}}}~~~(xx('x'w)yy)(y(x*zz*)z)y+{{+*{*z,||,+|+{-}}-,},|.~~.-~-}xxwwyyxxzzyy{{zz||{{}}||~~}}_````aaaabbbbccccddddeeeefff``__aa``bbaaccbbddcceeddffee              !! !""!"##"#$$#$%%$%&&%- ..- .!/ /. !/"0!0/!"0#1"10"#1$2#21#$2%3$32$%3&4%43%      !   "!!!#"""$###%$$$&%%%[;\<[<;[\<]=\=<\]=^>]>=]^>_?^?>^_?`@_@?_`@aA`A@`aAbBaBAa;I<J;JI;<J=K<KJ<=K>L=LK=>L?M>ML>?M@N?NM?@NAO@ON@AOBPAPOAIWJXIXWIJXKYJYXJKYLZKZYKLZM[L[ZLM[N\M\[MN\ O]N ]\N  O] P^O ^]O WeXfWfeWXfYgXgfXYgZhYhgYZh[iZihZ[i\j[ji[\j]k\kj\]k^l]lk]es fte tse  ft!guf!utf!!gu"hvg"vug""hv#iwh#wvh##iw$jxi$xwi$$jx%kyj%yxj%%ky&lzk&zyk&-s.ts.s..t/ut/t//u0vu0u00v1wv1v11w2xw2w22x3yx3x33y4zy4y4<;;;=<<<>===?>>>@???A@@@BAAAJIIIKJJJLKKKMLLLNMMMO N N NP O O  OXWWWYXXXZYYY[ZZZ\[[[] \ \\^ ]  ] ]f e e eg!f!f! fh"g"g"!gi#h#h#"hj$i$i$#ik%j%j%$jl&k&k&%kt .s. s.-su!/t/! t/ .tv"0u0"!u0!/uw#1v1#"v1"0vx$2w2$#w2#1wy%3x3%$x3$2xz&4y4&%y4%3yijiijkjjklkklmllmnmmnonnopooijjjjkkkkllllmmmmnnnnoooopppjjiikkjjllkkmmllnnmmoonnppoo  -.--./../0//010012 1 12 3!2! 23!4"3"!3)**)*++*+,,+,--,- ..- .!/ /. !/"0!0/!)7*8)87)*8+9*98*+9,:+:9+,:-;,;:,-;.<-<;-.</=.=<./=0>/>=/7E8F7FE78F9G8GF89G:H9HG9:H;I:IH:;I<J;JI;<J=K<KJ<=K>L=LK= ESFTETSEFTGUFUTFGUHVGVUGHVIWHWVHIWJXIXWIJXKYJYXJKYLZKZYK !   "!!!*)))+***,+++-,,,.---/...0///87779888:999;:::<;;;=<<<>===FEE EGFFFHGGGIHHHJIIIKJJJLKKK-a.b.ba..b/c/cb//c0d0dc00d1e1ed11e2f2fe22f3g3gf33g4h4hg4aobpapoabpcqbqpbcqdrcrqcdresdsrdes fte tse  ft!guf!utf!!gu"hvg"vug")o}*p~o*~}o**p~+qp+~p++q,rq,q,,r-sr-r--s.ts.s..t/ut/t//u0vu0u07}8~}8}88~9~9~99::::;;;;<<<<====>>>EFFFFGGGGHHHHIIIIJJJJKKKKLLLSTTTTUUUUVVVVWWWWXXXXYYYYZZZb.a.-a-ac/b/.b.bd0c0/c/ce1d10d0df2 e 21e 1eg3!f!32f!2 fh4"g"43g"3!gp*o*o*)oq+p+p+*pr,q,q,+qs-r-r-,rt .s. s.-su!/t/! t/ .tv"0u0"!u0!/u~*8}8*)}8)7}+9~9+*~9*8~,::,+:+9-;;-,;,:.<<.-<-;/==/.=.<0>>0/>/=8FF87F7E9GG98G8F:HH:9H9G;II;:I:H<JJ<;J;I=KK=<K<J>LL>=L=KFTTFETESGUUGFUFTHVVHGVGUIWWIHWHVJXXJIXIWKYYKJYJXLZZLKZKY                                        %&&%&''&'(('())()**)*++*+,,+%3&4%43%&4'5&54&'5(6'65'(6)7(76()7*8)87)*8+9*98*+9,:+:9+                   &%%%'&&&(''')(((*)))+***,+++ SATBSBASTBUCTCBTUCVDUDCUVDWEVEDVWEXFWFEWXFYGXGFXYGZHYHGY AO BPA POA  BP CQB QPB  CQ DRC RQC  DR ESD SRD  ESFTETSEFTGUFUTFGUHVGVUGO]P^O^]OP^Q_P_^PQ_R`Q`_QR`SaRa`RSaTbSbaSTbUcTcbTUcVdUdcU%]k&^l]&lk]&&^l'_m^'ml^''_m(`n_(nm_((`n)ao`)on`))ao*bpa*poa**bp+cqb+qpb++cq,drc,rqc,3ky4lzk4zyk44lz5m{l5{zl55m{6n|m6|{m66n|7o}n7}|n77o}8p~o8~}o88p~9qp9~p99q:rq:q:B A  A   AC B B  BD C C  CE D D  DFEE EGFFFHGGGP O  O OQ P  P PR Q  Q QS R  R RTS S SUTTTVUUU^&]&]&%]_'^'^'&^`(_(_('_a)`)`)(`b*a*a*)ac+b+b+*bd,c,c,+cl&4k4&%k4%3km'5l5'&l5&4ln(6m6('m6'5mo)7n7)(n7(6np*8o8*)o8)7oq+9p9+*p9*8pr,:q:,+q:+9qSTTTTUUUUVVVVWWWWXXXXYYYYZZZABBBBCCCCDDDDEEEEFFFFGGGGHHHOPPPPQQQQRRRRSSSSTTTTUUUUVVV]^^^^____````aaaabbbbccccdddkllllmmmmnnnnooooppppqqqqrrryzzzz{{{{||||}}}}~~~~TBBTSBSAUCCUTCTBVDDVUDUCWEEWVEVDXFFXWFWEYGGYXGXFZHHZYHYGBPPBAPAOCQQCBQBPDRRDCRCQESSEDSDRFTTFETESGUUGFUFTHVVHGVGUP^^PO^O]Q__QP_P^R``RQ`Q_SaaSRaR`TbbTSbSaUccUTcTbVddVUdUc^ll^]l]k_mm_^m^l`nn`_n_maooa`o`nbppbapaocqqcbqbpdrrdcrcqlzzlkzkym{{ml{lzn||nm|m{o}}on}n|p~~po~o}qqpp~rrqq                           !""!"##"#$$#$%%$%&&%&''&'(('             3/4030/3405141045162521562736326738474378495854895:69659/=0>/>=/0>1?0?>01?2@1@?12@ 3A2 A@2  3A 4B3 BA3  4B 5C4 CB4  5C 6D5 DC5 =K>L=LK=>L?M>ML>?M@N?NM?@NAO@ON@AOBPAPOABPCQBQPBCQDRCRQC!KY"LZK"ZYK""LZ#M[L#[ZL##M[$N\M$\[M$$N\%O]N%]\N%%O]&P^O&^]O&&P^'Q_P'_^P''Q_(R`Q(`_Q(0///100021113 2 2 24 3 3  35 4 4  46 5 5  5>===?>>>@???A @ @@B A  A AC B  B BD C  C CL"K"K"!KM#L#L#"LN$M$M$#MO%N%N%$NP&O&O&%OQ'P'P'&PR(Q(Q('Q3yg4zhy4hgy44zh5{iz5ihz55{i6|j{6ji{66|j7}k|7kj|77}k8~l}8lk}88~l9m~9ml~99m:n:nm:/gu0hvg0vug00hv1iwh1wvh11iw2jxi2xwi22jx3kyj3yxj33ky4lzk4zyk44lz5m{l5{zl55m{6n|m6|{m6=u>vu>u>>v?wv?v??w@xw@w@@xAyxAxAAyBzyByBBzC{zCzCC{D|{D{DKLLLLMMMMNNNNOOOOPPPPQQQQRRRYZZZZ[[[[\\\\]]]]^^^^____```h40g043g03/gi51h154h140hj62i265i251ik73j376j362jl84k487k473km95l598l584ln:6m6:9m695mv0>u>0/u>/=uw1?v?10v?0>vx2@w@21w@1?wy3AxA32xA2@xz4ByB43yB3Ay{5CzC54zC4Bz|6D{D65{D5C{>LL>=L=K?MM?>M>L@NN@?N?MAOOA@O@NBPPBAPAOCQQCBQBPDRRDCRCQLZZLKZKYM[[ML[LZN\\NM\M[O]]ON]N\P^^PO^O]Q__QP_P^R``RQ`Q_yzzzz{{{{||||}}}}~~~~ghhhhiiiijjjjkkkkllllmmmmnnnuvvvvwwwwxxxxyyyyzzzz{{{{|||zhhzyhyg{ii{zizh|jj|{j{i}kk}|k|j~ll~}l}kmm~m~lnnnmhvvhgvguiwwihwhvjxxjixiwkyykjyjxlzzlkzkym{{ml{lzn||nm|m{vvuuwwvvxxwwyyxxzzyy{{zz||{{          !"!!"#""#$##$%$$%&%%&'&&'(''   !! !""!"##"#$$# 5 6 65  6 7 76  7 887 8!9 98 !9":!:9!":#;";:"#;$<#<;#          !   "!!!#"""$###!Y+"Z,Y",+Y""Z,#[-Z#-,Z##[-$\.[$.-[$$\.%]/\%/.\%%]/&^0]&0/]&&^0'_1^'10^''_1(`2_(21_(+9,:+:9+,:-;,;:,-;.<-<;-.</=.=<./=0>/>=/0>1?0?>01?2@1@?19G:H9HG9:H;I:IH:;I <J; JI;  <J!=K<!KJ<!!=K">L="LK="">L#?M>#ML>##?M$@N?$NM?$5Gm6HnG6nmG66Hn7IoH7onH77Io8JpI8poI88Jp9KqJ9qpJ99Kq:LrK:rqK::Lr;MsL;srL;;Ms<NtM<tsM<,"+"!+!+-#,#",",.$-$#-#-/%.%$.$.0&/&%/%/1'0'&0&02(1('1'1:999;:::< ; ; ;=!<!<! <>"="="!=?#>#>#">@$?$?$#?H6G6G65GI7H7H76HJ 8I8 I87IK!9J9! J9 8JL":K:"!K:!9KM#;L;#"L;":LN$<M<$#M<#;MYUZVZVUZZV[W[WV[[W\X\XW\\X]Y]YX]]Y^Z^ZY^^Z_[_[Z__[`\`\[`+Uc,VdU,dcU,,Vd-WeV-edV--We.XfW.feW..Xf/YgX/gfX//Yg0ZhY0hgY00Zh1[iZ1ihZ11[i2\j[2ji[29cq:drc:rqc::dr;esd;srd;;es<fte<tse<<ft=guf=utf==gu>hvg>vug>>hv?iwh?wvh??iw@jxi@xwi@GqHrqHqHHrIsrIrIIsJtsJsJJtKutKtKKuLvuLuLLvMwvMvMMwNxwNwNmnnnnooooppppqqqqrrrrsssstttVZ,U,ZYU,Y+UW[-V-[ZV-Z,VX\.W.\[W.[-WY]/X/]\X/\.XZ^0Y0^]Y0]/Y[_1Z1_^Z1^0Z\`2[2`_[2_1[d,:c:,+c:+9ce-;d;-,d;,:df.<e<.-e<-;eg/=f=/.f=.<fh0>g>0/g>/=gi1?h?10h?0>hj2@i@21i@1?ir:HqH:9qH9Gqs;IrI;:rI:Hrt<JsJ<;sJ;Isu=KtK=<tK<Jtv>LuL>=uL=Kuw?MvM?>vM>Lvx@NwN@?wN?MwHnnHGnGmIooIHoHnJppJIpIoKqqKJqJpLrrLKrKqMssMLsLrNttNMtMsUVVVVWWWWXXXXYYYYZZZZ[[[[\\\cddddeeeeffffgggghhhhiiiijjjqrrrrssssttttuuuuvvvvwwwwxxx                    VVVUWWWVXXXWYYYXZZZY[[[Z\\\[VddVUdUcWeeWVeVdXffXWfWeYggYXgXfZhhZYhYg[ii[ZiZh\jj\[j[idrrdcrcqessedsdrfttfetesguugfufthvvhgvguiwwihwhvjxxjixiwrrqqssrrttssuuttvvuuwwvvxxww                                  5'6('6'56(7)(7(67)8*)8)78*9+*9*89+:,+:+9:,;-,;,:;-<.-<-; C5 D65 D5C  D6 E76 E6D  E7F87F7EF8G98G8FG9H:9H9GH:I;:I:HI;J<;J;IQCRDCRCQRDSEDSDRSETFETESTFUGFUFTUGVHGVGUVHWIHWHVWI XJI XIW 6 5 5  57 6 6  6877 79888:999;:::<;;;D C  C CE D  D DFE E EGFFFHGGGIHHHJ I I I'm_(n`_(n_m((n`)oa`)o`n))oa*pba*pao**pb+qcb+qbp++qc,rdc,rcq,,rd-sed-sdr--se.tfe.tes.5{m6|nm6|m{66|n7}on7}n|77}o8~po8~o}88~p9qp9p~99q:rq:q::r;sr;r;;s<ts<s<C{D|{D{DD|E}|E|EE}F~}F}FF~G~G~GGHHHHIIIIJJJQRRRRSSSSTTTTUUUUVVVVWWWWXXXn6(m(6'm65'mo7)n)7(n76(np8*o*8)o87)oq9+p+9*p98*pr:,q,:+q:9+qs;-r-;,r;:,rt<.s.<-s<;-s|D6{6D5{DC5{}E7|7E6|ED6|~F8}8F7}FE7}G9~9G8~GF8~H::H9HG9I;;I:IH:J<<J;JI;RDDRCRQCSEESDSRDTFFTETSEUGGUFUTFVHHVGVUGWIIWHWVHXJJXIXWI_````aaaabbbbccccddddeeeefffmnnnnooooppppqqqqrrrrssssttt{||||}}}}~~~~n``n_nm_oaao`on`pbbpapoaqccqbqpbrddrcrqcseesdsrdtfftetse|nn|m|{m}oo}n}|n~pp~o~}oqqp~prrqqssrrttss||{{}}||~~}}~~                    #$$#$%%$%&&%&''&'(('())()**)1#2$#2#12$3%$3$23%4&%4%34&5'&5&45'6('6'56(7)(7(67)8*)8)7?1@21@1?@2A32A2@A3B43B3AB4C54C4BC5D65D5CD6E76E6DE7F87F7EM?N@?N?MN@OA@O@NOAPBAPAOPBQCBQBPQCRDCRCQRDSEDSDRSETFETES[M\NM\M[\N]ON]N\]O^PO^O]^P_QP_P^_Q`RQ`Q_`RaSRaR`aSbTSbSa$###%$$$&%%%'&&&(''')(((*)))2111322243335444655576668777@???A@@@BAAACBBBDCCCEDDDFEEENMMMONNNPOOOQPPPRQQQSRRRTSSS                                                                                          # Q$ RQ$ Q# $ R% SR% R$ % S& TS& S% & T' UT' T& ' U( VU( U' ( V) WV) V( ) W * XW * W)  1 #  2 $ #  2 # 1   2 $ 3 % $ 3 $ 2 3 % 4 & % 4 % 3 4 & 5 ' & 5 & 4 5 ' 6 ( ' 6 ' 5 6 ( 7 ) ( 7 ( 6 7 )  8 * )  8 ) 7   ? 1  @ 2 1  @ 1 ?   @ 2  A 3 2  A 2 @   A 3  B 4 3  B 3 A   B 4  C 5 4  C 4 B   C 5  D 6 5  D 5 C   D 6  E 7 6  E 6 D   E 7  F 8 7  F 7 E  $  #  #   # % $  $  $ & %  % % ' &  & & ( '  ' ' ) (  ( ( *  )  )  ) 2   1    1    1 3  2   2    2 4  3  3   3 5  4  4   4 6  5  5   5 7  6  6   6 8   7   7   7 QM RN RN M RRN SO SO N SSO TP TP O TTP UQ UQ P UUQ VR VR Q VVR WS WS R WWS XT XT S X# [ M $ \ N M $ \ M [ $ $ \ N % ] O N % ] N \ % % ] O & ^ P O & ^ O ] & & ^ P ' _ Q P ' _ P ^ ' ' _ Q ( ` R Q ( ` Q _ ( ( ` R ) a S R ) a R ` ) ) a S * b T S * b S a * 1 i [ 2 j \ [ 2 j [ i 2 2 j \ 3 k ] \ 3 k \ j 3 3 k ] 4 l ^ ] 4 l ] k 4 4 l ^ 5 m _ ^ 5 m ^ l 5 5 m _ 6 n ` _ 6 n _ m 6 6 n ` 7 o a ` 7 o ` n 7 7 o a 8 p b a 8 p a o 8 ? w i @ x j i @ x i w @ @ x j A y k j A y j x A A y k B z l k B z k y B B z l C { m l C { l z C C { m D | n m D | m { D D | n E } o n E } n | E E } o F ~ p o F ~ o } F N $ RM R$ QM $ # QM O % SN S% RN % $ RN P & TO T& SO & % SO Q ' UP U' TP ' & TP R ( VQ V( UQ ( ' UQ S ) WR W) VR ) ( VR T * XS X* WS * ) WS \ 2 $ [ $ 2 # [ 2 1 # [ ] 3 % \ % 3 $ \ 3 2 $ \ ^ 4 & ] & 4 % ] 4 3 % ] _ 5 ' ^ ' 5 & ^ 5 4 & ^ ` 6 ( _ ( 6 ' _ 6 5 ' _ a 7 ) ` ) 7 ( ` 7 6 ( ` b 8 * a * 8 ) a 8 7 ) a j @ 2 i 2 @ 1 i @ ? 1 i k A 3 j 3 A 2 j A @ 2 j l B 4 k 4 B 3 k B A 3 k m C 5 l 5 C 4 l C B 4 l n D 6 m 6 D 5 m D C 5 m o E 7 n 7 E 6 n E D 6 n p F 8 o 8 F 7 o F E 7 o                             M N N N N O O O O P P P P Q Q Q Q R R R R S S S S T T T [ \ \ \ \ ] ] ] ] ^ ^ ^ ^ _ _ _ _ ` ` ` ` a a a a b b b i j j j j k k k k l l l l m m m m n n n n o o o o p p p w x x x x y y y y z z z z { { { { | | | | } } } } ~ ~ ~ N  N  N M  O  O  O N  P  P  P O  Q  Q  Q P  R  R  R Q  S  S  S R  T  T  T S  \ N N \ M \ [ M ] O O ] N ] \ N ^ P P ^ O ^ ] O _ Q Q _ P _ ^ P ` R R ` Q ` _ Q a S S a R a ` R b T T b S b a S j \ \ j [ j i [ k ] ] k \ k j \ l ^ ^ l ] l k ] m _ _ m ^ m l ^ n ` ` n _ n m _ o a a o ` o n ` p b b p a p o a x j j x i x w i y k k y j y x j z l l z k z y k { m m { l { z l | n n | m | { m } o o } n } | n ~ p p ~ o ~ } o ;[<\[<[;<\=]\=\<=]>^]>]=>^?_^?^>?_@`_@_?@`Aa`A`@AaBbaBaA I; J<; J;I J< K=< K<J K= L>= L=K L> M?> M>L M? N@? N?M N@ OA@ O@N OA PBA PAO WI XJI XIW XJ YKJ YJX YK ZLK ZKY ZL [ML [LZ [M \NM \M[ \N ]ON ]N\ ]O ^PO ^O] eW fXW fWe fX gYX gXf gY hZY hYg hZ i[Z iZh i[ j\[ j[i j\ k]\ k\j k] l^] l]k se tfe tes tf ugf uft ug vhg vgu vh wih whv wi xji xiw xj ykj yjx yk zlk zky s ts s t ut t u vu u v wv v w xw w x yx x y zy y < ; ; ;= < < <> = = =? > > >@ ? ? ?A @ @ @B A A AJ I I IK J J JL K K KM L L LN M M MO N N NP O O OX W W WY X X XZ Y Y Y[ Z Z Z\ [ [ [] \ \ \^ ] ] ]f e e eg f f fh g g gi h h hj i i ik j j jl k k kt s s su t t tv u u uw v v vx w w wy x x xz y y y                                                                                                      ?  @ ?  ?   @  A @  @   A  B A  A   B  C B  B   C  D C  C   D  E D  D   E  F E  E                                                                                                                              ?  w @ x w @ w  @ @ x A ! y x A ! x A A ! y B " z y B " y ! B B " z C # { z C # z " C C # { D $ | { D $ { # D D $ | E % } | E % | $ E E % } F & ~ } F & } % F -  .  .  - . / ! / . / ! 0 " ! 0 ! / 0 " 1 # " 1 " 0 1 # 2 $ # 2 # 1 2 $ 3 % $ 3 $ 2 3 % 4 & % 4 % 3  ; -  < . -  < - ;   < .  = / .  = . <   = /  > 0 /  > / =   > 0  ? 1 0  ? 0 >   ? 1  @ 2 1  @ 1 ?   @ 2 A 3 2 A 2 @ A 3 B 4 3 B 3 A  I ;  J < ;  J ; I   J <  K = <  K < J   K =  L > =  L = K   L >  M ? >  M > L   M ?  N @ ?  N ? M   N @  O A @  O @ N   O A  P B A  P A O  @  @ ?  ?  ! A A @ @ " B ! B A ! A ! # C " C B " B " $ D # D C # C # % E $ E D $ D $ & F % F E % E % .  -  -   - /  .  .   . 0  /  /   / 1  0  0   0 2  1  1   1 3 2 2  2 4 3 3 3 <   ;    ;    ; =   <    <    < >   =    =    = ?   >    >    > @   ?    ?    ? A  @   @    @ B  A  A   A w W x X x X W x x X y Y y Y X y y Y z Z z Z Y z z Z { [ { [ Z { { [ | \ | \ [ | | \ } ] } ] \ } } ] ~ ^ ~ ^ ] ~  e W f X W f W e f X ! g Y X ! g X f ! ! g Y " h Z Y " h Y g " " h Z # i [ Z # i Z h # # i [ $ j \ [ $ j [ i $ $ j \ % k ] \ % k \ j % % k ] & l ^ ] & l ] k & - s e . t f e . t e s . . t f / u g f / u f t / / u g 0 v h g 0 v g u 0 0 v h 1 w i h 1 w h v 1 1 w i 2 x j i 2 x i w 2 2 x j 3 y k j 3 y j x 3 3 y k 4 z l k 4 z k y 4 ; s < t s < s < < t = u t = t = = u > v u > u > > v ? w v ? v ? ? w @ x w @ w @ @ x A y x A x A A y B z y B y B I J J J J K K K K L L L L M M M M N N N N O O O O P P P X x W x w W  w W Y ! y X y ! x X ! x X Z " z Y z " y Y " ! y Y [ # { Z { # z Z # " z Z \ $ | [ | $ { [ $ # { [ ] % } \ } % | \ % $ | \ ^ & ~ ] ~ & } ] & % } ] f . e .  e . -  e g / ! f ! / f / . f h 0 " g " 0 ! g 0 / ! g i 1 # h # 1 " h 1 0 " h j 2 $ i $ 2 # i 2 1 # i k 3 % j % 3 $ j 3 2 $ j l 4 & k & 4 % k 4 3 % k t < . s . < - s < ; - s u = / t / = . t = < . t v > 0 u 0 > / u > = / u w ? 1 v 1 ? 0 v ? > 0 v x @ 2 w 2 @ 1 w @ ? 1 w y A 3 x 3 A 2 x A @ 2 x z B 4 y 4 B 3 y B A 3 y J < < J ; J I ; K = = K < K J < L > > L = L K = M ? ? M > M L > N @ @ N ? N M ? O A A O @ O N @ P B B P A P O A a b ba b c cb c d dc d e ed e f fe f g gf g h hg W oaX pbaX paoX X pbY qcbY qbpY Y qcZ rdcZ rcqZ Z rd[ sed[ sdr[ [ se\ tfe\ tes\ \ tf] ugf] uft] ] ug^ vhg^ vgu^ e }of ~pof ~o}f f ~pg qpg p~g g qh rqh qh h ri sri ri i sj tsj sj j tk utk tk k ul vul ul s }t ~}t }t t ~u ~u ~u u v v v v w w w w x x x x y y y y z z z                                           bX a X aX W acY b Y bY X bdZ c Z cZ Y ce[ d [ d[ Z df\ e \ e\ [ eg] f ] f] \ fh^ g ^ g^ ] gpf X oX f W of e W oqg Y pY g X pg f X prh Z qZ h Y qh g Y qsi [ r[ i Z ri h Z rtj \ s\ j [ sj i [ suk ] t] k \ tk j \ tvl ^ u^ l ] ul k ] u~t f }f t e }t s e }u g ~g u f ~u t f ~v h h v g v u g w i i w h w v h x j j x i x w i y k k y j y x j z l l z k z y k  t t s  s  u u t  t  v v u  u  w w v  v  x x w  w  y y x  x  z z y  y                                                                         I  J I  I   J  K J  J   K  L K  K   L  M L  L   M  N M  M   N  O N  N   O  P O  O                                                                                                           !   !  !  "   "  !                                                                           I ) J * J * ) J J * K + K + * K K + L , L , + L L , M - M - , M M - N . N . - N N . O / O / . O O / P 0 P 0 / P 7 ) 8 * ) 8 ) 7 8 * 9 + * 9 * 8 9 + : , + : + 9 : , ; - , ; , : ; - < . - < - ; < . = / . = . < = / > 0 / > / = E 7 F 8 7 F 7 E F 8  G 9 8  G 8 F   G 9  H : 9  H 9 G   H :  I ; :  I : H   I ;  J < ;  J ; I   J <  K = <  K < J   K =  L > =  L = K  S E  T F E  T E S   T F  U G F  U F T   U G  V H G  V G U   V H  W I H  W H V   W I  X J I  X I W   X J  Y K J  Y J X   Y K  Z L K  Z K Y   a S  b T S  b S a   b T  c U T  c T b   c U  d V U  d U c   d V  e W V  e V d   e W f X W f W e f X ! g Y X ! g X f ! ! g Y " h Z Y " h Y g " * J ) J I ) I ) + K * K J * J * , L + L K + K + - M , M L , L , . N - N M - M - / O . O N . N . 0 P / P O / O / 8 7 7 7 9  8  8  8 :  9  9   9 ;  :  :   : <  ;  ;   ; =  <  <   < >  =  =   = F  E  E  E G   F   F   F H   G    G    G I   H    H    H J   I    I    I K   J    J    J L   K    K    K T   S   S   S U   T    T    T V   U    U    U W   V    V    V X  W   W   W Y !  X  !  X !  X Z "  Y  "  Y " !  Y                      ) * * * * + + + + , , , , - - - - . . . . / / / / 0 0 0 7 8 8 8 8 9 9 9 9 : : : : ; ; ; ; < < < < = = = = > > > E F F F F G G G G H H H H I I I I J J J J K K K K L L L S T T T T U U U U V V V V W W W W X X X X Y Y Y Y Z Z Z a b b b b c c c c d d d d e e e e f f f f g g g g h h h *  * * ) +  + + * ,  , , + -  - - , .  . . - /  / / . 0  0 0 / 8 * * 8 ) 8 7 ) 9 + + 9 * 9 8 * : , , : + : 9 + ; - - ; , ; : , < . . < - < ; - = / / = . = < . > 0 0 > / > = / F 8 8 F 7 F E 7 G 9 9 G 8 G F 8 H : : H 9 H G 9 I ; ; I : I H : J < < J ; J I ; K = = K < K J < L > > L = L K = T F F T E T S E U G G U F U T F V H H V G V U G W I I W H W V H X J J X I X W I Y K K Y J Y X J Z L L Z K Z Y K b T T b S b a S c U U c T c b T d V V d U d c U e W W e V e d V f X X f W f e W g Y Y g X g f X h Z Z h Y h g Y o p p o p q q p q r r q r s s r s t t s t u u t u v v u  } ~ ~ } ~   ~   o } p ~ } p } p p ~ q  ~ q ~ q q  r  r  r r s s s s t t t t u u u u v v v ~ p } p } p o }  q ~ q ~ q p ~ r  r  r q  s s s r t t t s u u u t v v v u } ~ ~ ~ ~     ~ ~ ~ }    ~  ~ ~ } }   ~ ~                      ! ! " ! !  a  b a  a   b  c b  b   c  d c  c   d  e d  d   e f e e f !  g f !  f ! !  g "  h g "  g  "                                                     %  &   &  % &  '   '  & '  (   (  ' (  )   )  ( )  *   *  ) *  +   +  * +  ,   ,  + 3 % 4 & % 4 % 3 4 & 5 ' & 5 & 4 5 ' 6 ( ' 6 ' 5 6 ( 7 ) ( 7 ( 6 7 ) 8 * ) 8 ) 7 8 * 9 + * 9 * 8 9 + : , + : + 9                    ! !  "  " !  !                                       & % % % ' & & & ( ' ' ' ) ( ( ( * ) ) ) + * * * , + + + a b b b b c c c c d d d d e e e e f f f f g g g g h h h                                                                          % & & & & ' ' ' ' ( ( ( ( ) ) ) ) * * * * + + + + , , , 3 4 4 4 4 5 5 5 5 6 6 6 6 7 7 7 7 8 8 8 8 9 9 9 9 : : :  b b a  a  c c b  b  d d c  c  e e d  d  f f e  e  g g  f  f  h h  g   g                                                                         &   &  & %  '   '  ' &  (   (  ( '  )   )  ) (  *   *  * )  +   +  + *  ,   ,  , +  4 & & 4 % 4 3 % 5 ' ' 5 & 5 4 & 6 ( ( 6 ' 6 5 ' 7 ) ) 7 ( 7 6 ( 8 * * 8 ) 8 7 ) 9 + + 9 * 9 8 * : , , : + : 9 + o p o o p q p p q r q q r s r r s t s s t u t t u v u u o A p B p B A p p B q C q C B q q C r D r D C r r D s E s E D s s E t F t F E t t F u G u G F u u G v H v H G v A B A A B C B B C D C C D E D D E F E E F G F F G H G G B p A p o A o A C q B q p B p B D r C r q C q C E s D s r D r D F t E t s E s E G u F u t F t F H v G v u G u G O P P O P Q Q P Q R R Q R S S R S T T S T U U T U V V U A ] O B ^ P O B ^ O ] B B ^ P C _ Q P C _ P ^ C C _ Q D ` R Q D ` Q _ D D ` R E a S R E a R ` E E a S F b T S F b S a F F b T G c U T G c T b G G c U H d V U H d U c H '] (^ ] (] '(^ )_ ^ )^ ()_ *` _ *_ )*` +a ` +` *+a ,b a ,a +,b -c b -b ,-c .d c .c -P B O B O B A O Q C P C P C B P R D Q D Q D C Q S E R E R E D R T F S F S F E S U G T G T G F T V H U H U H G U ^ B ] B A ] A ] _ C ^ C B ^ B ^ ` D _ D C _ C _ a E ` E D ` D ` b F a F E a E a c G b G F b F b d H c H G c G c k l l k l m m l m n n m n o o n o p p o p q q p q r r q O y k P z l k P z k y P P z l Q { m l Q { l z Q Q { m R | n m R | m { R R | n S } o n S } n | S S } o T ~ p o T ~ o } T T ~ p U  q p U  p ~ U U  q V r q V q  V ] y ^ z y ^ y ^ ^ z _ { z _ z _ _ { ` | { ` { ` ` | a } | a | a a } b ~ } b } b b ~ c  ~ c ~ c c  d  d  d '_ (` (` _((` )a )a `))a *b *b a**b +c +c b++c ,d ,d c,,d -e -e d--e .f .f e.l P k P k P O k m Q l Q l Q P l n R m R m R Q m o S n S n S R n p T o T o T S o q U p U p U T p r V q V q V U q z ^ P y P ^ O y ^ ] O y { _ Q z Q _ P z _ ^ P z | ` R { R ` Q { ` _ Q { } a S | S a R | a ` R | ~ b T } T b S } b a S }  c U ~ U c T ~ c b T ~ d V  V d U  d c U  (^ ^ (] ('] )_ _ )^ )(^ *` ` *_ *)_ +a a +` +*` ,b b ,a ,+a -c c -b -,b .d d .c .-c 3 4 3 3 4 5 4 4 5 6 5 5 6 7 6 6 7 8 7 7 8 9 8 8 9 : 9 9 k l l l l m m m m n n n n o o o o p p p p q q q q r r r y z z z z { { { { | | | | } } } } ~ ~ ~ ~     _ ` ` `` a a aa b b bb c c cc d d dd e e ee f f f l l l k m m m l n n n m o o o n p p p o q q q p r r r q z l l z k z y k { m m { l { z l | n n | m | { m } o o } n } | n ~ p p ~ o ~ } o  q q  p  ~ p r r q  q z z y y { { z z | | { { } } | | ~ ~ } }   ~ ~   ` ` `_ a a a` b b ba c c cb d d dc e e ed f f fe 3 4 4 4 4 5 5 5 5 6 6 6 6 7 7 7 7 8 8 8 8 9 9 9 9 : : :                                                                                                          4 4 3  3  5 5 4  4  6 6 5  5  7 7 6  6  8 8 7  7  9 9 8  8  : : 9  9                                                                                                 !!""##$$%%&&'/=/=0>0>1?1?2@2@ 3A 3A 4B 4B 5C =K=K>L>L?M?M@N@NAOAOBPBPCQ !KY!KY"LZ"LZ#M[#M[$N\$N\%O]%O]&P^&P^'Q_==>>??@@A A B B C  K!K!L"L"M#M#N$N$O%O%P&P&Q' /gu/gu0hv0hv1iw1iw2jx2jx3ky3ky4lz4lz5m{ =u=u>v>v?w?w@x@xAyAyBzBzC{ KKLLMMNNOOPPQ YYZZ[[\\]]^^_ u=/u=/v>0v>0w?1w?1x@2x@2yA3yA3zB4zB4{C5 K=K=L>L>M?M?N@N@OAOAPBPBQC YKYKZLZL[M[M\N\N]O]O^P^P_Q gghhiijjkkllm uuvvwwxxyyzz{  ugugvhvhwiwixjxjykykzlzl{m uuvvwwxxyyzz{   !!""#++,,-- . .!/!/"0"0#1+9+9,:,:-;-;.<.</=/=0>0>1?9G9G:H:H;I;I<J<J=K=K>L>L?MGUGUHVHVIWIWJXJXKYKYLZLZM[  !!""#++,,--..//00199::;;<<==>>?GGHHIIJJKKLLMccddeeffgghhi!q!q"r"r#s#s$t$t%u%u&v&v'wcqcqdrdresesftftguguhvhviwqcqcrdrdsesetftfugugvhvhwi !Y!Y"Z"Z#[#[$\$\%]%]&^&^'_ !qqrrssttuuvvw!" q!q!r"r"s#s#t$t$u%u%v&v&w'!qqrrssttuuvvw #YYZZ[[\\]]^^_ #$!$%"%&# YYZZ[[\\]]^^_$! %"!'#'($()      %)*      &*+''(())**++,,-'#($#)%$      *&%,U5U5V6V6W7W7X8X8Y9Y9Z:Z:[;',-5C5C6D6D7E7E8F8F9G9G:H:H;I(-.CQCQDRDRESESFTFTGUGUHVHVIW)./ Q_ Q_ R` R` Sa SaTbTbUcUcVdVdWe*/0_m_m`n`naoaobpbpcqcqdrdres+01'm{'m{(n|(n|)o})o}*p~*p~+q+q,r,r-s,'5566778899::;-('CCDDEEFFGGHHI.)(Q Q R R S S TTUUVVW/*)_ _ ` ` a a bbccdde0+*m'm'n(n(o)o)p*p*q+q+r,r,s-2ccddeeffgghhi3ccddeeffgghhi23432ccddeeffgghhi"535646753643"&858969:7:;         85"965:76&+<''(())**++,,-8<=##$$%%&&''(()9=>#1#1$2$2%3%3&4&4'5'5(6(6)7:>?1?1?2@2@3A3A4B4B5C5C6D6D7E;?@?M?M@N@N AO AO BP BP CQ CQ DR DR ES<8&=98##$$%%&&''(()>:91122334455667?;:??@@A A B B C C D D E +1A'{['{[(|\(|\)}])}]*~^*~^+_+_,`,`-a<AB[i[i\j\j]k]k^l^l_m_m`n`nao=BC#iw#iw$jx$jx%ky%ky&lz&lz'm{'m{(n|(n|)o}>CD1w1w2x2x3y3y4z4z5{5{6|6|7}?DE??@@AABBCCDDE@EFMMNNOOPPQQRRSA<+['['\(\(])])^*^*_+_+`,`,a-B=<i#i#j$j$k%k%l&l&m'm'n(n(o)C>=w1#w1#x2$x2$y3%y3%z4&z4&{5'{5'|6(|6(}7)D?>?1?1@2@2A3A3B4B4C5C5D6D6E7E@?M?M?N@N@OAOAPBPBQCQCRDRDSE2G24HGHIHG247JHJKIKLJH4KIH7;M          JMN KNO  !!""##$$%LOP-- . .!/!/"0"0#1#1$2$2%3MJ7 NKJOLK  !!""##$$%;@QM;M;N<N< O= O= P> P> Q? Q? R@ R@ SAMQR;I;I<J<J=K=K>L>L?M?M@N@N AONRSIWIWJXJXKYKYLZLZM[M[N\N\O]OSTWeWe Xf Xf!Yg!Yg"Zh"Zh#[i#[i$\j$\j%]kPTU-es-es.ft.ft/gu/gu0hv0hv1iw1iw2jx2jx3kyQM;;;<<= = > > ? ? @ @ A  RNMIIJJKKLLMMNNO SONWWX X Y!Y!Z"Z"[#[#\$\$]%TPOe-e-f. f. g/!g/!h0"h0"i1#i1#j2$j2$k3%@FVMMNNOOPPQQRRSQVW;;<<==>>??@@ARWXIIJJKKLLMMNNOSXYWWXXYYZZ[[\\]TYZeeffgghhiijjkUZ[ssttuuvvwwxxyVQ@;M;M<N<N=O=O>P>P?Q?Q@R@RASWRQI;I;J<J<K=K=L>L>M?M?N@N@OAXSRWIWIXJXJYKYKZLZL[M[M\N\N]OYTSeWeWfXfXgYgYhZhZi[i[j\j\k]ZUTsesetftfugugvhvhwiwixjxjykG\GI]\]^]\GIL_]_`  ^`a    !_]I`^]  LPb-)-).*.*/+/+0,0,1-1-2.2.3/_bc)7)7*8*8+9+9,:,:-;-;.<.</=`cd 7E 7E8F8F9G9G:H:H;I;I<J<J=KadeESESFTFTGUGUHVHVIWIW JX JX!KYb_L))**++,,--../c`_7 7 8899::;;<<=da`E E FFGGHHIIJ J K!PUf-sa-sa.tb.tb/uc/uc0vd0vd1we1we2xf2xf3ygbfg)ao)ao*bp*bp+cq+cq,dr,dr-es-es.ft.ft/gucgh7o}7o}8p~8p~9q9q:r:r;s;s<t<t=udhiE}E}F~F~GGHHIIJJKeijSSTTUUVVWWXXYfbPa)-a)-b*.b*.c+/c+/d,0d,0e-1e-1f.2f.2g/3gcbo7)o7)p8*p8*q9+q9+r:,r:,s;-s;-t<.t<.u=/hdc}E7}E7~F8~F8G9G9H:H:I;I;J<J<K=iedSESETFTFUGUGVHVHWIWIXJXJYKU[kssttuuvvwwxxyfklaabbccddeeffgglmooppqqrrssttuhmn}}~~inojopkfUasasbtbtcucudvdvewewfxfxgylgfoaoapbpbqcqcrdrdsesetftfugmhg}o}o~p~pqqrrssttunih}}~~oji\\^qq     q\^ar            !qrs          s//001122 3 3 4 4 5rq^          sq     aetS%S%T&T&U'U'V(V(W)W) X* X*!Y+rtu %3 %3 &4 &4 '5 '5 (6 (6 )7 )7*8*8+9suv3A3A4B4B5C5C6D6D7E7E8F8F9Gv /Ag/Ag0Bh0Bh1Ci1Ci2Dj2Dj3Ek3Ek4Fl4Fl5Gmtra% % & & ' ' ( ( ) ) * * +!usr3 3 4 4 5 5 6 6 7 7 889vsA/A/B0B0C1C1D2D2E3E3F4F4G5ejwSOSOTPTPUQUQVRVRWSWSXTXTYUtwx%O]%O]&P^&P^'Q_'Q_(R`(R`)Sa)Sa*Tb*Tb+Ucuxy3]k3]k4^l4^l5_m5_m6`n6`n7ao7ao8bp8bp9cqvyzAkyAkyBlzBlzCm{Cm{Dn|Dn|Eo}Eo}Fp~Fp~Gq zgygyhzhzi{i{j|j|k}k}l~l~mwteO%SO%SP&TP&TQ'UQ'UR(VR(VS)WS)WT*XT*XU+Yxut]3%]3%^4&^4&_5'_5'`6(`6(a7)a7)b8*b8*c9+yvukA3kA3lB4lB4mC5mC5nD6nD6oE7oE7pF8pF8qG9z vygAygAzhBzhB{iC{iC|jD|jD}kE}kE~lF~lFmGjp{w{|OOPPQQRRSSTTUx|}]]^^__``aabbcy}~kkllmmnnooppqz~yyzz{{||}}~~{wjOOPPQQRRSSTTU|xw]O]O^P^P_Q_Q`R`RaSaSbTbTcU}yxk]k]l^l^m_m_n`n`oaoapbpbqc~zyykykzlzl{m{m|n|n}o}o~p~pqzyyzz{{||}}~~               /!/!0"0"1#1#2$2$3%3%4&4&5'=/=/>0>0?1?1@2@2 A3 A3 B4 B4 C5K=K=L>L>M?M?N@N@OAOAPBPBQC//0011223 3 4 4 5 ==>>??@@A A B B C !gY!gY"hZ"hZ#i[#i[$j\$j\%k]%k]&l^&l^'m_/ug/ug0vh0vh1wi1wi2xj2xj3yk3yk4zl4zl5{m=u=u>v>v?w?w@x@xAyAyBzBzC{KKLLMMNNOOPPQg!/g!/h"0h"0i#1i#1j$2j$2k%3k%3l&4l&4m'5u/=u/=v0>v0>w1?w1?x2@x2@y3Ay3Az4Bz4B{5C=K=K>L>L?M?M@N@NAOAOBPBPCQYYZZ[[\\]]^^_gghhiijjkkllmuuvvwwxxyyzz{YgYgZhZh[i[i\j\j]k]k^l^l_mguguhvhviwiwjxjxkykylzlzm{uuvvwwxxyyzz{  !!""#++,,--. . /!/!0"0"1#9+9+:,:,;-;-<.<.=/=/>0>0?1G9G9H:H:I;I;J<J<K=K=L>L>M?UGUGVHVHWIWIXJXJYKYKZLZL[M  !!""#++,,--..//00199::;;<<==>>?GGHHIIJJKKLLM                                                     K K L L M M N N! O! O" P" P# Q +   +   ,   ,   -   -   .  .  / !  / !  0 "  0 "  1 #  9 +  9 +  : ,  : ,  ; -  ; -  < .  < .  = /  = /  > 0  > 0  ? 1               !  !  "  "  #  +   +   ,   ,   -   -   .   .   /   /   0   0   1   KG KG LH LH MI MI NJ NJ OK OK PL PL QM  U G  U G  V H  V H  W I  W I X J X J ! Y K ! Y K " Z L " Z L # [ M + c U + c U , d V , d V - e W - e W . f X . f X / g Y / g Y 0 h Z 0 h Z 1 i [ 9 q c 9 q c : r d : r d ; s e ; s e < t f < t f = u g = u g > v h > v h ? w i G K G K H L H L I M I M J N J N K O! K O! L P" L P" M Q# U  + U  + V  , V  , W  - W  - X . X . Y ! / Y ! / Z " 0 Z " 0 [ # 1 c + 9 c + 9 d , : d , : e - ; e - ; f . < f . < g / = g / = h 0 > h 0 > i 1 ?              G  G  H H I I J J K K L L M U U V V W W X X Y Y Z Z [ c c d d e e f f g g h h i q q r r s s t t u u v v w  G  G H H I I J J K K L L M G U G U H V H V I W I W J X J X K Y K Y L Z L Z M [ U c U c V d V d W e W e X f X f Y g Y g Z h Z h [ i c q c q d r d r e s e s f t f t g u g u h v h v i w ,5U5U6V6V7W7W8X8X9Y9Y:Z:Z;[-, C5 C5 D6 D6 E7 E7 F8 F8 G9 G9 H: H: I;.- QC QC RD RD SE SE TF TF UG UG VH VH WI/. _Q _Q `R `R aS aS bT bT cU cU dV dV eW0/ m_ m_ n` n` oa oa pb pb qc qc rd rd se10 {m {m |n |n }o }o ~p ~p q q r r s,5 5 6 6 7 7 8 8 9 9 : : ; -C C D D E E F F G G H H I .Q Q R R S S T T U U V V W /_ _ ` ` a a b b c c d d e 0m m n n o o p p q q r r s                                                      9  9  :  :  ;  ;  <  <  =  =  >  >  ?                                    9  q 9  q :  r :  r ;  s ;  s <  t <  t =  u =  u >  v >  v ?  w '  '  (  (  )  )  *  *  +  +  ,  ,  -  5 ' 5 ' 6 ( 6 ( 7 ) 7 ) 8 * 8 *  9 +  9 +  : ,  : ,  ; - C 5 C 5 D 6 D 6 E 7 E 7  F 8  F 8  G 9  G 9  H :  H :  I ;  9  9  :  :  ;  ;  <  <  =  =  >  >  ? ' ' ( ( ) ) * * +  +  ,  ,  -  5 5 6 6 7 7 8  8  9   9   :   :   ;   q Q q Q r R r R s S s S t T t T u U u U v V v V w W  _ Q  _ Q  ` R  ` R  a S  a S  b T  b T  c U  c U  d V  d V  e W ' m _ ' m _ ( n ` ( n ` ) o a ) o a * p b * p b + q c + q c , r d , r d - s e 5 { m 5 { m 6 | n 6 | n 7 } o 7 } o 8 ~ p 8 ~ p 9  q 9  q : r : r ; s C { C { D | D | E } E } F ~ F ~ G  G  H H I Q q  Q q  R r  R r  S s  S s  T t  T t  U u  U u  V v  V v  W w  _  ' _  ' `  ( `  ( a  ) a  ) b  * b  * c  + c  + d  , d  , e  - m ' 5 m ' 5 n ( 6 n ( 6 o ) 7 o ) 7 p * 8 p * 8 q + 9 q + 9 r , : r , : s - ; { 5 C { 5 C | 6 D | 6 D } 7 E } 7 E ~ 8 F ~ 8 F  9 G  9 G : H : H ; I A1 [{ [{ \| \| ]} ]} ^~ ^~ _ _ ` ` aBAQ i[Q i[R j\R j\S k]S k]T l^T l^U m_U m_V n`V n`W oaCB_ wi_ wi` xj` xja yka ykb zlb zlc {mc {md |nd |ne }oDCm wm wn xn xo yo yp zp zq {q {r |r |s }ED{ { | | } } ~ ~      FE             A[ Q [ Q \ R \ R ] S ] S ^ T ^ T _ U _ U ` V ` V a W BiQ _ iQ _ jR ` jR ` kS a kS a lT b lT b mU c mU c nV d nV d oW e Cw_ m w_ m x` n x` n ya o ya o zb p zb p {c q {c q |d r |d r }e s Dm { m { n | n | o } o } p ~ p ~ q  q  r r s E{ { | | } } ~ ~                          C C D D E E  F  F  G  G  H  H  I                                 C # C # D $ D $ E % E % F & F & G ' G ' H ( H ( I ) 1 # 1 # 2 $ 2 $ 3 % 3 % 4 & 4 & 5 ' 5 ' 6 ( 6 ( 7 ) ? 1 ? 1 @ 2 @ 2 A 3 A 3 B 4 B 4 C 5 C 5 D 6 D 6 E 7  M ?  M ?  N @  N @ O A O A P B P B Q C Q C R D R D S E  [ M  [ M  \ N  \ N  ] O  ] O  ^ P  ^ P  _ Q  _ Q  ` R  ` R  a S # C # C $ D $ D % E % E & F & F ' G ' G ( H ( H ) I 1 1 2 2 3 3 4 4 5 5 6 6 7 ?  ?  @  @  A A B B C C D D E M   M   N   N   O  O  P  P  Q  Q  R  R  S  VF             WV# # $ $ % % & & ' ' ( ( ) XW1 1 2 2 3 3 4 4 5 5 6 6 7 YX? ? @ @ A A B B C C D D E ZYM M N N O O P P Q Q R R S [Z[ [ \ \ ] ] ^ ^ _ _ ` ` a V #  #  $  $  %  %  &  &  '  '  (  (  ) W# 1 # 1 $ 2 $ 2 % 3 % 3 & 4 & 4 ' 5 ' 5 ( 6 ( 6 ) 7 X1 ? 1 ? 2 @ 2 @ 3 A 3 A 4 B 4 B 5 C 5 C 6 D 6 D 7 E Y? M ? M @ N @ N A O A O B P B P C Q C Q D R D R E S ZM [ M [ N \ N \ O ] O ] P ^ P ^ Q _ Q _ R ` R ` S a i i j j k k l l m m n n o w w x x y y z z { { | | } i w i w j x j x k y k y l z l z m { m { n | n | o } w i w i x j x j y k y k z l z l { m { m | n | n } o w w x x y y z z { { | | } w w x x y y z z { { | | } w w x x y y z z { { | | }               [  [  \  \  ]  ]  ^  ^  _  _  `  `  a                                            !  !  "  "  #  #  $  $  %  -  -  . . / ! / ! 0 " 0 " 1 # 1 # 2 $ 2 $ 3 %                                         ! ! " " # # $ $ % k[[ [ \ \ ] ] ^ ^ _ _ ` ` a lk             ml             nm             on    ! ! " " # # $ $ % po- - . . / / 0 0 1 1 2 2 3 k[ [ \ \ ] ] ^ ^ _ _ ` ` a l                         m                          n       !  !  "  "  #  #  $  $  % o -  -  .  . ! / ! / " 0 " 0 # 1 # 1 $ 2 $ 2 % 3 i i j j k k l l m m n n o i ; i ; j < j < k = k = l > l > m ? m ? n @ n @ o A ; ; < < = = > > ? ? @ @ A ; i ; i < j < j = k = k > l > l ? m ? m @ n @ n A o  I I J J K K L L M M N N O ; W I ; W I < X J < X J = Y K = Y K > Z L > Z L ? [ M ? [ M @ \ N @ \ N A ] O !W !W "X "X #Y #Y $Z $Z %[ %[ &\ &\ '] I ; I ; J < J < K = K = L > L > M ? M ? N @ N @ O A W ; W ; X < X < Y = Y = Z > Z > [ ? [ ? \ @ \ @ ] A  e e f f g g h h i i j j k I s e I s e J t f J t f K u g K u g L v h L v h M w i M w i N x j N x j O y k W s W s X t X t Y u Y u Z v Z v [ w [ w \ x \ x ] y !Y !Y "Z "Z #[ #[ $\ $\ %] %] &^ &^ '_ e I e I f J f J g K g K h L h L i M i M j N j N k O s I W s I W t J X t J X u K Y u K Y v L Z v L Z w M [ w M [ x N \ x N \ y O ] W ! W ! X " X " Y # Y # Z $ Z $ [ % [ % \ & \ & ] ' - - . . / / 0 0 1 1 2 2 3 e e f f g g h h i i j j k s s t t u u v v w w x x y Y Y Z Z [ [ \ \ ] ] ^ ^ _ e e f f g g h h i i j j k e s e s f t f t g u g u h v h v i w i w j x j x k y s s t t u u v v w w x x y Y Y Z Z [ [ \ \ ] ] ^ ^ _{p- - . . / / 0 0 1 1 2 2 3 |{             }|             ~}             ~             {- - . . / / 0 0 1 1 2 2 3 |             }             ~                          tests/meshes/vtk/000077500000000000000000000000001456244072500143215ustar00rootroot00000000000000tests/meshes/vtk/00_image.vtk000066400000000000000000000032101456244072500164240ustar00rootroot00000000000000# vtk DataFile Version 3.4 Image ASCII DATASET STRUCTURED_POINTS DIMENSIONS 10 10 1 ORIGIN 0.0 0.0 0.0 SPACING 0.5 0.5 0.0 POINT_DATA 100 SCALARS transmissivity float 1 LOOKUP_TABLE default 0.298739662586 0.279131445489 0.291060629758 0.209081029997 0.167312512876 0.17295265379 0.2100958905 0.203211077558 0.194905559894 0.194502141846 0.131241923907 0.19249787806 0.200954738051 0.155585026284 0.182841950501 0.187871957767 0.207598852496 0.195911898513 0.208253505857 0.1920442551 0.202996450184 0.252721080135 0.23671796761 0.233189895756 0.270186702166 0.272931816024 0.270380706188 0.235920429082 0.295855745957 0.262264695111 0.259718930583 0.230059095126 0.234317359927 0.237685617976 0.214377778761 0.212776562413 0.191132637109 0.190419933446 0.19304295094 0.219138618799 0.280266184206 0.232735721002 0.2013628867 0.242265369993 0.204605952014 0.217593655281 0.257883000267 0.265031911042 0.252164884194 0.274015475987 0.258132330746 0.258587001316 0.20202912732 0.177675067263 0.172328034934 0.207081436701 0.280701097154 0.236035028008 0.22751839086 0.198225008225 0.166977802309 0.167918014212 0.171268784021 0.162286321399 0.225587172718 0.255948616943 0.169888780058 0.131652207091 0.164775824684 0.225934163991 0.235147380819 0.306821054112 0.26003544081 0.247473520841 0.24507626514 0.199585971691 0.146278300724 0.146749272746 0.227855782454 0.243324810464 0.263984406253 0.202267248848 0.185525164757 0.207851666271 0.22789498338 0.175890885834 0.158555750876 0.251900632165 0.213176490915 0.204000194234 0.250290544772 0.2187337482 0.211795398808 0.185664474197 0.174563178783 0.174648363874 0.166720082135 0.12097483942 0.122984046496 0.205734861691 tests/meshes/vtk/01_image.vtk000066400000000000000000000145571456244072500164450ustar00rootroot00000000000000# vtk DataFile Version 4.2 vtk output ASCII DATASET STRUCTURED_POINTS DIMENSIONS 7 7 3 ASPECT_RATIO 1 1 1 ORIGIN 0 0 0 CELL_DATA 72 FIELD FieldData 2 pressure1 1 72 double 0.8677104542 0.51636185155 0.60688284218 0.46963710959 0.84631932221 0.19738233512 0.10449260542 0.13325513899 0.1261254424 0.92811591687 0.85276551296 0.87436138227 0.57021773734 0.64484045379 0.83211192182 0.91742765699 0.78576559398 0.61298629515 0.6735725119 0.95343444683 0.94452291226 0.75495718491 0.92715036051 0.41195114237 0.16643423413 0.77370647925 0.87340165423 0.25739115973 0.25705504591 0.31147847687 0.7299432699 0.70197478982 0.1637118679 0.3955116108 0.5419513408 0.043992262805 0.63705083954 0.15316737283 0.81736094123 0.62336803143 0.50731765079 0.11081170015 0.56418617227 0.91414438791 0.052267630295 0.11663225967 0.98749503289 0.61230653547 0.95160106712 0.36307324908 0.93814204076 0.47078090661 0.3778094117 0.98835590606 0.041782676901 0.41421973924 0.51073980308 0.84948398985 0.70052446738 0.064860319334 0.36908298368 0.55362015347 0.13069604232 0.11563651603 0.034805442219 0.22238653602 0.24687431521 0.94102825318 0.89631139818 0.49057691045 0.83937323407 0.40715670809 METADATA INFORMATION 0 pressure2 1 72 double 0.8677104542 0.51636185155 0.60688284218 0.46963710959 0.84631932221 0.19738233512 0.10449260542 0.13325513899 0.1261254424 0.92811591687 0.85276551296 0.87436138227 0.57021773734 0.64484045379 0.83211192182 0.91742765699 0.78576559398 0.61298629515 0.6735725119 0.95343444683 0.94452291226 0.75495718491 0.92715036051 0.41195114237 0.16643423413 0.77370647925 0.87340165423 0.25739115973 0.25705504591 0.31147847687 0.7299432699 0.70197478982 0.1637118679 0.3955116108 0.5419513408 0.043992262805 0.63705083954 0.15316737283 0.81736094123 0.62336803143 0.50731765079 0.11081170015 0.56418617227 0.91414438791 0.052267630295 0.11663225967 0.98749503289 0.61230653547 0.95160106712 0.36307324908 0.93814204076 0.47078090661 0.3778094117 0.98835590606 0.041782676901 0.41421973924 0.51073980308 0.84948398985 0.70052446738 0.064860319334 0.36908298368 0.55362015347 0.13069604232 0.11563651603 0.034805442219 0.22238653602 0.24687431521 0.94102825318 0.89631139818 0.49057691045 0.83937323407 0.40715670809 METADATA INFORMATION 0 POINT_DATA 147 FIELD FieldData 2 temp1 1 147 double 0.19932609943 0.080484975432 0.62271676952 0.17526854106 0.85265478881 0.20618656795 0.84349132399 0.038892471051 0.90607584362 0.53145615434 0.31918008657 0.20474882787 0.026379692258 0.48104509843 0.50001234209 0.045244591207 0.83508077518 0.47561534276 0.40962142531 0.0011841612877 0.14709018583 0.75095831727 0.48417916779 0.18271087896 0.54656071738 0.75066701975 0.92200696569 0.99769339208 0.26117515176 0.085311465967 0.1646683261 0.81218612228 0.63122274863 0.56536002542 0.61634033728 0.51835579684 0.4278608922 0.630029077 0.61492773995 0.54908405353 0.7708722292 0.25359302007 0.70233431709 0.61075920411 0.9125950554 0.55867195058 0.028337602721 0.75342955411 0.35627445538 0.65575668043 0.10189677317 0.81150143817 0.61299601434 0.21606925506 0.60478711464 0.83937102764 0.85003752009 0.044045564549 0.46397193546 0.76703318221 0.060487798272 0.089849800165 0.6698869959 0.49180368025 0.054588170455 0.60657339138 0.99430585956 0.95520254464 0.41486965842 0.31728314337 0.7863231829 0.021234945228 0.51786325975 0.072245341545 0.7311841733 0.0059933017956 0.14530623862 0.70174168053 0.047421832096 0.65318254961 0.23720001553 0.58673678257 0.22685717667 0.12009824017 0.038425067107 0.035546247175 0.10844204481 0.46533179621 0.19527170909 0.014046989322 0.98575901443 0.12321432463 0.04330563787 0.31288353454 0.77184910491 0.50055628109 0.91733177324 0.94877989401 0.98760860859 0.62370960235 0.1802712889 0.60612390385 0.27937860958 0.78119102642 0.2098678809 0.23795094593 0.87305172717 0.022913016055 0.85021930614 0.34946437346 0.20389954341 0.64959363365 0.10151151857 0.95849443411 0.18591031788 0.26712287986 0.21679083654 0.30027647079 0.92909265289 0.058716366373 0.41706634312 0.62893832977 0.438984896 0.27390875927 0.058657266281 0.05994697265 0.39632622578 0.24057772072 0.26926772847 0.90228743973 0.7462902986 0.55399859345 0.28386352495 0.02032014315 0.84847748999 0.089787722754 0.094645324833 0.70209677424 0.9284726152 0.20015337624 0.61003086407 0.15306703884 0.10979782787 0.12908663141 0.050329141049 0.48476689788 0.72757728194 METADATA INFORMATION 0 temp2 1 147 double 0.19932609943 0.080484975432 0.62271676952 0.17526854106 0.85265478881 0.20618656795 0.84349132399 0.038892471051 0.90607584362 0.53145615434 0.31918008657 0.20474882787 0.026379692258 0.48104509843 0.50001234209 0.045244591207 0.83508077518 0.47561534276 0.40962142531 0.0011841612877 0.14709018583 0.75095831727 0.48417916779 0.18271087896 0.54656071738 0.75066701975 0.92200696569 0.99769339208 0.26117515176 0.085311465967 0.1646683261 0.81218612228 0.63122274863 0.56536002542 0.61634033728 0.51835579684 0.4278608922 0.630029077 0.61492773995 0.54908405353 0.7708722292 0.25359302007 0.70233431709 0.61075920411 0.9125950554 0.55867195058 0.028337602721 0.75342955411 0.35627445538 0.65575668043 0.10189677317 0.81150143817 0.61299601434 0.21606925506 0.60478711464 0.83937102764 0.85003752009 0.044045564549 0.46397193546 0.76703318221 0.060487798272 0.089849800165 0.6698869959 0.49180368025 0.054588170455 0.60657339138 0.99430585956 0.95520254464 0.41486965842 0.31728314337 0.7863231829 0.021234945228 0.51786325975 0.072245341545 0.7311841733 0.0059933017956 0.14530623862 0.70174168053 0.047421832096 0.65318254961 0.23720001553 0.58673678257 0.22685717667 0.12009824017 0.038425067107 0.035546247175 0.10844204481 0.46533179621 0.19527170909 0.014046989322 0.98575901443 0.12321432463 0.04330563787 0.31288353454 0.77184910491 0.50055628109 0.91733177324 0.94877989401 0.98760860859 0.62370960235 0.1802712889 0.60612390385 0.27937860958 0.78119102642 0.2098678809 0.23795094593 0.87305172717 0.022913016055 0.85021930614 0.34946437346 0.20389954341 0.64959363365 0.10151151857 0.95849443411 0.18591031788 0.26712287986 0.21679083654 0.30027647079 0.92909265289 0.058716366373 0.41706634312 0.62893832977 0.438984896 0.27390875927 0.058657266281 0.05994697265 0.39632622578 0.24057772072 0.26926772847 0.90228743973 0.7462902986 0.55399859345 0.28386352495 0.02032014315 0.84847748999 0.089787722754 0.094645324833 0.70209677424 0.9284726152 0.20015337624 0.61003086407 0.15306703884 0.10979782787 0.12908663141 0.050329141049 0.48476689788 0.72757728194 METADATA INFORMATION 0 tests/meshes/vtk/02_structured.vtk000066400000000000000000000312401456244072500175540ustar00rootroot00000000000000# vtk DataFile Version 4.2 vtk output ASCII DATASET STRUCTURED_GRID DIMENSIONS 7 7 3 POINTS 147 double 0.016097836025 -0.0066555606458 -0.009106647449 0.1733969032 0.0090399163471 0.031757449436 0.33911962646 0.0062874519805 0.045462455612 0.51075862185 0.0051257278606 -0.029177116516 0.66533800385 0.013108560268 0.021271506318 0.83769838526 -0.010959765226 -0.036359143999 0.98504259859 0.0047546018538 0.037050545331 0.013907309336 0.18246627742 -0.046818381932 0.18237891839 0.17280584132 0.0075819263041 0.34160966101 0.17207531769 0.00033680576228 0.50236559154 0.15418839664 -0.028289303738 0.65397837769 0.17017370868 0.04317322173 0.84949887936 0.15216477824 -0.0029299702212 0.99356665017 0.1770215724 0.0017804475498 -0.00615227565 0.34418527946 0.0081030082193 0.18010898176 0.31722833449 0.028447390308 0.32276500029 0.34201857872 -0.016800280505 0.50807503845 0.34942519486 -0.034778344998 0.6775474319 0.31984603087 0.0089720258128 0.84729482517 0.3380957034 -0.0067066948018 0.99778934884 0.33289718497 -0.037154068295 -0.0046982195539 0.51099100874 0.026708283818 0.17025938284 0.51610470142 -0.014625934125 0.34967543289 0.51050560084 -0.0056288607216 0.51630177359 0.49084931472 0.034521905043 0.65975943881 0.48570355408 0.03361898188 0.84535056542 0.50894076316 0.0042127103501 1.0009500488 0.51289667312 0.044010949234 -0.00062435261137 0.66720370788 -0.039056045075 0.18310410081 0.65601094071 0.016454461598 0.33508947575 0.65192817519 -0.021969451183 0.49039746817 0.65967511716 -0.025093635557 0.66562052027 0.66587432699 0.0052201201525 0.81850101297 0.66795922618 0.0022057548268 1.0086206694 0.66311947564 0.011916832912 0.014075847621 0.83326223107 0.017165200178 0.16793797389 0.84864274331 0.014327767801 0.32842270252 0.83439817252 0.017658447612 0.50390288265 0.82542010683 -0.028739776196 0.65773881722 0.84416812106 0.0031585656079 0.84077196999 0.84873968954 -0.013238234486 0.99315793374 0.84546739623 0.030260034366 0.0011339276995 1.0009399919 0.016604400368 0.161138787 1.0146364726 -0.018236235337 0.3257754929 1.011335575 0.043021284072 0.5135458276 0.99392427679 -0.038683127984 0.66209330283 1.0066475641 -0.045988329763 0.84097006872 0.98758829167 -0.00020137200397 1.0147581381 0.99225296045 -0.012100243863 -0.0053978491539 0.0065439697198 0.51836477299 0.16075286646 -0.0097629422425 0.47058952605 0.33887020292 0.011350790233 0.53746850822 0.48574130015 -0.0020366546289 0.50191286689 0.65572014649 0.013807237767 0.48375058233 0.8286386126 0.014895959291 0.52733015129 1.0132117409 0.0027836366985 0.53247640091 -0.0054687440332 0.17303097363 0.52858610778 0.15742413014 0.15506885862 0.46464570524 0.32601624685 0.17061990442 0.4896244983 0.48980400894 0.17908195358 0.51230355275 0.65594053528 0.16880734052 0.48971676102 0.84853513403 0.17476649675 0.48797754997 0.99042706129 0.15662090744 0.49256653888 0.0019434558926 0.34302192065 0.49936580467 0.17613165273 0.34471838518 0.54189882581 0.33600899704 0.34443755922 0.50142421043 0.50895519771 0.32548817805 0.5014986656 0.65743998465 0.34081949026 0.54565134373 0.83567477275 0.32610244517 0.49228933485 1.0129068439 0.31794200907 0.52093193269 0.016073625036 0.48486895082 0.47221600206 0.17768514791 0.48743891922 0.5368466837 0.32492097448 0.48844429481 0.45489056792 0.50003238085 0.50768809536 0.51980795881 0.65600972293 0.50704920527 0.46723968272 0.83211554696 0.495375411 0.53579643575 0.98712402729 0.50507430278 0.47326845807 -0.00096293597575 0.66989639799 0.52757706696 0.16705943198 0.67924747016 0.47690763262 0.33740643281 0.66711601652 0.52621217856 0.49032456835 0.68114181972 0.49023234967 0.67426929968 0.66604729849 0.45317248132 0.82816868139 0.66292566539 0.54257962857 1.0085781987 0.67245996766 0.53233887191 -0.014926130627 0.82676956937 0.51649185431 0.15429890054 0.83935985212 0.45543127707 0.33099872077 0.83414017462 0.53402917956 0.48587430366 0.81933839437 0.51956711517 0.67963890486 0.84251881063 0.54729295716 0.82821127204 0.84785102758 0.52317708288 1.0054908084 0.82130274444 0.53657655345 -0.0066630333791 1.0157021684 0.54740452099 0.17342776222 0.99154207105 0.50179414233 0.3377092001 0.99656626995 0.47004175737 0.51284211707 1.0142119526 0.52212713485 0.65844114141 1.0048894149 0.50890097353 0.84533619888 1.0144229156 0.46577786174 0.9987748856 0.98568696397 0.54777213491 0.012888379129 0.0036885122952 0.95686958603 0.15357341885 -0.00065272064772 1.0262438715 0.33084580824 -0.012703473288 0.97483592167 0.51497209512 -0.0080521912046 1.0474399204 0.65806115248 -0.0023892088967 0.9909297062 0.83433168465 0.0077882065681 1.0276363672 0.98751789355 -0.015274787969 0.96520219509 0.012499901777 0.16593426678 0.97297871598 0.17903934469 0.15965855978 1.0150660153 0.31733710435 0.15073370233 0.96573021298 0.48605751426 0.15225681334 0.95915124858 0.66222984704 0.17792898839 0.97189336808 0.84328956432 0.16275335658 1.0073620281 1.0115100333 0.15153424052 0.98375124428 0.014793864125 0.3262260491 1.0309538307 0.18084271085 0.34945243625 1.0325615197 0.34304794555 0.31807601105 0.97398668319 0.51101813833 0.32185478716 1.0066933164 0.65616899442 0.33103228005 1.0055869756 0.81917854206 0.3358492536 0.99294344768 0.98891622685 0.31700080099 0.97101092853 -0.0089239267162 0.51637444872 1.0427526453 0.16813267386 0.51400173705 0.95825287153 0.33116685779 0.49959174349 1.0092050071 0.49314264493 0.49476947159 0.9869242523 0.66407957958 0.50646028997 0.9679152694 0.84067943458 0.49837411967 0.97954023236 0.98752341704 0.50942169697 0.97808465982 -0.0095755796684 0.68303966073 1.0495865001 0.16515442322 0.66479655691 0.95383350655 0.34526248577 0.67569920919 1.0343110894 0.50952068108 0.67065665572 1.0142876209 0.67854006544 0.67600911734 1.0428590006 0.82446214933 0.65979837887 1.0219414642 0.9844952586 0.67762181541 1.0187000185 -0.015338152602 0.82775377543 1.0151882645 0.17222253348 0.83560593105 1.0343837216 0.34616504528 0.84903909119 0.95739113825 0.49197639208 0.82213793931 1.0275791115 0.66911848575 0.81981520446 1.0067994817 0.84912558532 0.83750537796 1.0371248509 0.99463189989 0.82488770538 0.96105625502 0.0038184510469 1.0085641489 1.0432839637 0.15493784139 0.99441967197 1.0456896885 0.32000013409 0.98764375732 0.96541431975 0.51076144504 0.99287470313 0.95482439237 0.66112983526 0.98708057706 0.96853110168 0.84110227276 0.99637224249 0.99355281029 0.9957977991 0.99972130129 0.95543345973 METADATA INFORMATION 1 NAME L2_NORM_RANGE LOCATION vtkDataArray DATA 2 0.0196562 1.70409 CELL_DATA 72 FIELD FieldData 2 pressure1 1 72 double 0.13795852842 0.98039815271 0.10503754932 0.56626638522 0.96500924554 0.56046976315 0.079983972734 0.58105215018 0.58169340716 0.73007629678 0.38185702564 0.84247618396 0.66446283803 0.54833912486 0.049465659777 0.30332955473 0.76474601713 0.217329204 0.57776437415 0.62245938112 0.12074733274 0.13687847854 0.44494998211 0.95257764869 0.95490828371 0.051995397266 0.46979080479 0.44659958769 0.58862913817 0.20730383598 0.3810851279 0.39268992004 0.77525984955 0.38349863597 0.031496502929 0.63753663639 0.16304690985 0.95619314363 0.37786053731 0.094818892515 0.31637379495 0.3892127265 0.96224381919 0.36789802527 0.15250598575 0.56489044555 0.75706877783 0.91414670708 0.80978710761 0.45469246223 0.26310806104 0.23791097635 0.49177825303 0.98001386831 0.85561706219 0.25061800099 0.65687075091 0.45132291264 0.14397228247 0.65085350344 0.30767470134 0.89154954303 0.80948890197 0.93611774845 0.078629417722 0.2826173675 0.86934277701 0.29405340228 0.63487937666 0.40551511911 0.11533128603 0.35473096858 METADATA INFORMATION 0 pressure2 1 72 double 0.13795852842 0.98039815271 0.10503754932 0.56626638522 0.96500924554 0.56046976315 0.079983972734 0.58105215018 0.58169340716 0.73007629678 0.38185702564 0.84247618396 0.66446283803 0.54833912486 0.049465659777 0.30332955473 0.76474601713 0.217329204 0.57776437415 0.62245938112 0.12074733274 0.13687847854 0.44494998211 0.95257764869 0.95490828371 0.051995397266 0.46979080479 0.44659958769 0.58862913817 0.20730383598 0.3810851279 0.39268992004 0.77525984955 0.38349863597 0.031496502929 0.63753663639 0.16304690985 0.95619314363 0.37786053731 0.094818892515 0.31637379495 0.3892127265 0.96224381919 0.36789802527 0.15250598575 0.56489044555 0.75706877783 0.91414670708 0.80978710761 0.45469246223 0.26310806104 0.23791097635 0.49177825303 0.98001386831 0.85561706219 0.25061800099 0.65687075091 0.45132291264 0.14397228247 0.65085350344 0.30767470134 0.89154954303 0.80948890197 0.93611774845 0.078629417722 0.2826173675 0.86934277701 0.29405340228 0.63487937666 0.40551511911 0.11533128603 0.35473096858 METADATA INFORMATION 0 POINT_DATA 147 FIELD FieldData 2 temp1 1 147 double 0.75023536049 0.154708685 0.6273602213 0.30175482123 0.92254998434 0.089076740076 0.025287843123 0.37685724918 0.076809625199 0.99486465488 0.017172268283 0.12954509502 0.95339440924 0.13110635282 0.49969090164 0.63720996334 0.08856119452 0.69090885019 0.21226712372 0.034083195757 0.37151013113 0.58830683975 0.50767692592 0.86544378728 0.48254945355 0.9468299584 0.51427839019 0.4070569932 0.024021552562 0.33321767926 0.64695361204 0.085823132238 0.97189032231 0.41045785695 0.073433693377 0.31239171126 0.319060392 0.74354845141 0.98278182919 0.99821039821 0.87446758805 0.94711144761 0.29705499059 0.49418872785 0.067030942278 0.8860269077 0.13286120491 0.46133436519 0.46578066258 0.82148145133 0.020924397894 0.82685114851 0.10065334804 0.36475133035 0.52068525602 0.17279068289 0.045065193484 0.098446399493 0.55558292092 0.78585837389 0.23328187527 0.62096676061 0.16742452658 0.96233672454 0.88190385933 0.30434086402 0.77567526464 0.086635714033 0.49595480903 0.31517172346 0.76226683408 0.15361320544 0.22325246351 0.52400041894 0.76030701583 0.68857500684 0.75058253364 0.65029287163 0.9647594872 0.0010202630388 0.53480133747 0.73645798211 0.66522544405 0.98286413592 0.39401448762 0.083885504284 0.66063864323 0.73336542804 0.037902948881 0.35287082071 0.48594617628 0.11367411678 0.12959748521 0.49154031154 0.67497204442 0.36306596385 0.90980600643 0.19441857986 0.20868246346 0.83309798327 0.49451340436 0.46994311507 0.20945743958 0.90180499386 0.5882724815 0.59257716926 0.36687922328 0.031175163596 0.59139143764 0.22074049374 0.25009561491 0.42839567802 0.73397672723 0.27750910732 0.10343172891 0.29795508391 0.5824967726 0.49255555201 0.41040440901 0.51740971604 0.27642443648 0.17821611139 0.51489622537 0.11142441873 0.96543388855 0.82264080865 0.15457351543 0.351476427 0.1313250572 0.3373358227 0.97473064492 0.72094042884 0.84408819099 0.82331232023 0.52003273245 0.97129609052 0.55093322641 0.60515474675 0.37546482768 0.17590731957 0.30494883209 0.068149684854 0.11239873611 0.88408229271 0.2256313757 0.91498208381 0.71068656904 METADATA INFORMATION 0 temp2 1 147 double 0.75023536049 0.154708685 0.6273602213 0.30175482123 0.92254998434 0.089076740076 0.025287843123 0.37685724918 0.076809625199 0.99486465488 0.017172268283 0.12954509502 0.95339440924 0.13110635282 0.49969090164 0.63720996334 0.08856119452 0.69090885019 0.21226712372 0.034083195757 0.37151013113 0.58830683975 0.50767692592 0.86544378728 0.48254945355 0.9468299584 0.51427839019 0.4070569932 0.024021552562 0.33321767926 0.64695361204 0.085823132238 0.97189032231 0.41045785695 0.073433693377 0.31239171126 0.319060392 0.74354845141 0.98278182919 0.99821039821 0.87446758805 0.94711144761 0.29705499059 0.49418872785 0.067030942278 0.8860269077 0.13286120491 0.46133436519 0.46578066258 0.82148145133 0.020924397894 0.82685114851 0.10065334804 0.36475133035 0.52068525602 0.17279068289 0.045065193484 0.098446399493 0.55558292092 0.78585837389 0.23328187527 0.62096676061 0.16742452658 0.96233672454 0.88190385933 0.30434086402 0.77567526464 0.086635714033 0.49595480903 0.31517172346 0.76226683408 0.15361320544 0.22325246351 0.52400041894 0.76030701583 0.68857500684 0.75058253364 0.65029287163 0.9647594872 0.0010202630388 0.53480133747 0.73645798211 0.66522544405 0.98286413592 0.39401448762 0.083885504284 0.66063864323 0.73336542804 0.037902948881 0.35287082071 0.48594617628 0.11367411678 0.12959748521 0.49154031154 0.67497204442 0.36306596385 0.90980600643 0.19441857986 0.20868246346 0.83309798327 0.49451340436 0.46994311507 0.20945743958 0.90180499386 0.5882724815 0.59257716926 0.36687922328 0.031175163596 0.59139143764 0.22074049374 0.25009561491 0.42839567802 0.73397672723 0.27750910732 0.10343172891 0.29795508391 0.5824967726 0.49255555201 0.41040440901 0.51740971604 0.27642443648 0.17821611139 0.51489622537 0.11142441873 0.96543388855 0.82264080865 0.15457351543 0.351476427 0.1313250572 0.3373358227 0.97473064492 0.72094042884 0.84408819099 0.82331232023 0.52003273245 0.97129609052 0.55093322641 0.60515474675 0.37546482768 0.17590731957 0.30494883209 0.068149684854 0.11239873611 0.88408229271 0.2256313757 0.91498208381 0.71068656904 METADATA INFORMATION 0 tests/meshes/vtk/03_rectilinear.vtk000066400000000000000000000152041456244072500176540ustar00rootroot00000000000000# vtk DataFile Version 4.2 vtk output ASCII DATASET RECTILINEAR_GRID DIMENSIONS 7 7 3 X_COORDINATES 7 double 0 0.16666666667 0.33333333333 0.5 0.66666666667 0.83333333333 1 METADATA INFORMATION 0 Y_COORDINATES 7 double 0 0.16666666667 0.33333333333 0.5 0.66666666667 0.83333333333 1 METADATA INFORMATION 0 Z_COORDINATES 3 double 0 0.5 1 METADATA INFORMATION 0 CELL_DATA 72 FIELD FieldData 2 pressure1 1 72 double 0.68481602841 0.7408984814 0.17688921297 0.63393817883 0.044208263843 0.82976770229 0.89378590019 0.075092558663 0.43180151434 0.035131859465 0.134643422 0.47990950523 0.80192557645 0.7468449724 0.20534806841 0.92834914766 0.88198675703 0.45615571918 0.042484004691 0.87550368235 0.68700029846 0.22131595768 0.75649463584 0.44563818901 0.069957941663 0.46754458779 0.86074528691 0.95202479824 0.2375718218 0.35798944994 0.19527332554 0.74519124313 0.95125108946 0.93581255986 0.94507096115 0.01704049028 0.89259582525 0.8848127866 0.88185041179 0.63730034541 0.040485258291 0.86773991306 0.40879356878 0.63753083929 0.72482238033 0.34846270951 0.32066055117 0.66800047263 0.35008675445 0.57675212419 0.44109084634 0.62252503984 0.74068575587 0.84557747344 0.89870057861 0.63543896047 0.87469776486 0.97029262447 0.84717730236 0.41587290249 0.14356359296 0.99228835994 0.71032127168 0.5956867493 0.92442066026 0.7386054156 0.60352799914 0.095139821159 0.3034024004 0.11421540773 0.67402382509 0.48084460187 METADATA INFORMATION 0 pressure2 1 72 double 0.68481602841 0.7408984814 0.17688921297 0.63393817883 0.044208263843 0.82976770229 0.89378590019 0.075092558663 0.43180151434 0.035131859465 0.134643422 0.47990950523 0.80192557645 0.7468449724 0.20534806841 0.92834914766 0.88198675703 0.45615571918 0.042484004691 0.87550368235 0.68700029846 0.22131595768 0.75649463584 0.44563818901 0.069957941663 0.46754458779 0.86074528691 0.95202479824 0.2375718218 0.35798944994 0.19527332554 0.74519124313 0.95125108946 0.93581255986 0.94507096115 0.01704049028 0.89259582525 0.8848127866 0.88185041179 0.63730034541 0.040485258291 0.86773991306 0.40879356878 0.63753083929 0.72482238033 0.34846270951 0.32066055117 0.66800047263 0.35008675445 0.57675212419 0.44109084634 0.62252503984 0.74068575587 0.84557747344 0.89870057861 0.63543896047 0.87469776486 0.97029262447 0.84717730236 0.41587290249 0.14356359296 0.99228835994 0.71032127168 0.5956867493 0.92442066026 0.7386054156 0.60352799914 0.095139821159 0.3034024004 0.11421540773 0.67402382509 0.48084460187 METADATA INFORMATION 0 POINT_DATA 147 FIELD FieldData 2 temp1 1 147 double 0.15184421213 0.44742653081 0.095466301934 0.54763321187 0.19324596196 0.81336074461 0.89618473408 0.44987667885 0.80114149531 0.16315685215 0.99812561567 0.9037730004 0.75268298488 0.53006709174 0.18576458996 0.51199463388 0.41105329773 0.24239596208 0.85846691194 0.43413524711 0.47267822282 0.60641499485 0.51355839313 0.43287135185 0.47640559997 0.97288961494 0.61429042394 0.70581048665 0.065936841167 0.63314967535 0.60012026764 0.18594694771 0.16823928819 0.080521273321 0.68190240412 0.75080745507 0.5353777274 0.96784897933 0.12995469679 0.71846181243 0.66743195557 0.72575238303 0.088554580153 0.20320467526 0.87482370275 0.65065914812 0.12594994752 0.02725564106 0.15049339894 0.68657697094 0.88013131699 0.94249582775 0.18122748926 0.46658147111 0.44637444367 0.69280768437 0.92473788911 0.82529254604 0.15755822605 0.0051687595707 0.61460578104 0.7234585607 0.56905630427 0.75900412905 0.47414886317 0.54394429824 0.34211996751 0.98196177072 0.92221924883 0.77527841623 0.63382558964 0.14924749942 0.32768385259 0.2895643701 0.10320564521 0.15081282933 0.49996009749 0.32673651659 0.75383874553 0.8571015154 0.56124108275 0.34393414122 0.9432200479 0.061201799696 0.9985863168 0.60908020181 0.73346253495 0.99490699616 0.15026452495 0.51409752559 0.75630422794 0.92491239667 0.1099003329 0.57226406431 0.23060786115 0.29605317945 0.034194329357 0.59689719066 0.069093550567 0.12779281759 0.39340161394 0.2860681582 0.25854783332 0.18894330876 0.85827171176 0.40775520287 0.76044080381 0.74732740091 0.32219448353 0.39770096191 0.58102050637 0.05189883446 0.99509596567 0.9026782597 0.068170246003 0.16427309592 0.74588518831 0.4044565828 0.58493877163 0.47228021091 0.65929383313 0.85792127496 0.33328956984 0.3600731556 0.27493365102 0.95807327535 0.90241394706 0.93271836171 0.44865942466 0.46441902328 0.20433162022 0.56895928481 0.032408533118 0.53155053595 0.3759268701 0.12034935601 0.12251117325 0.2785867957 0.73229626025 0.0004345801637 0.67193163546 0.81041906487 0.92307518563 0.047169703428 0.57421165038 0.36437130081 0.20314746133 METADATA INFORMATION 0 temp2 1 147 double 0.15184421213 0.44742653081 0.095466301934 0.54763321187 0.19324596196 0.81336074461 0.89618473408 0.44987667885 0.80114149531 0.16315685215 0.99812561567 0.9037730004 0.75268298488 0.53006709174 0.18576458996 0.51199463388 0.41105329773 0.24239596208 0.85846691194 0.43413524711 0.47267822282 0.60641499485 0.51355839313 0.43287135185 0.47640559997 0.97288961494 0.61429042394 0.70581048665 0.065936841167 0.63314967535 0.60012026764 0.18594694771 0.16823928819 0.080521273321 0.68190240412 0.75080745507 0.5353777274 0.96784897933 0.12995469679 0.71846181243 0.66743195557 0.72575238303 0.088554580153 0.20320467526 0.87482370275 0.65065914812 0.12594994752 0.02725564106 0.15049339894 0.68657697094 0.88013131699 0.94249582775 0.18122748926 0.46658147111 0.44637444367 0.69280768437 0.92473788911 0.82529254604 0.15755822605 0.0051687595707 0.61460578104 0.7234585607 0.56905630427 0.75900412905 0.47414886317 0.54394429824 0.34211996751 0.98196177072 0.92221924883 0.77527841623 0.63382558964 0.14924749942 0.32768385259 0.2895643701 0.10320564521 0.15081282933 0.49996009749 0.32673651659 0.75383874553 0.8571015154 0.56124108275 0.34393414122 0.9432200479 0.061201799696 0.9985863168 0.60908020181 0.73346253495 0.99490699616 0.15026452495 0.51409752559 0.75630422794 0.92491239667 0.1099003329 0.57226406431 0.23060786115 0.29605317945 0.034194329357 0.59689719066 0.069093550567 0.12779281759 0.39340161394 0.2860681582 0.25854783332 0.18894330876 0.85827171176 0.40775520287 0.76044080381 0.74732740091 0.32219448353 0.39770096191 0.58102050637 0.05189883446 0.99509596567 0.9026782597 0.068170246003 0.16427309592 0.74588518831 0.4044565828 0.58493877163 0.47228021091 0.65929383313 0.85792127496 0.33328956984 0.3600731556 0.27493365102 0.95807327535 0.90241394706 0.93271836171 0.44865942466 0.46441902328 0.20433162022 0.56895928481 0.032408533118 0.53155053595 0.3759268701 0.12034935601 0.12251117325 0.2785867957 0.73229626025 0.0004345801637 0.67193163546 0.81041906487 0.92307518563 0.047169703428 0.57421165038 0.36437130081 0.20314746133 METADATA INFORMATION 0 tests/meshes/vtk/04_rectilinear.vtk000066400000000000000000000045731456244072500176640ustar00rootroot00000000000000# vtk DataFile Version 4.2 vtk output ASCII DATASET RECTILINEAR_GRID DIMENSIONS 10 4 1 X_COORDINATES 10 double 0 0.11111111111 0.22222222222 0.33333333333 0.44444444444 0.55555555556 0.66666666667 0.77777777778 0.88888888889 1 Y_COORDINATES 4 double 0 0.66666666667 1.3333333333 2 Z_COORDINATES 1 double 0 CELL_DATA 27 FIELD FieldData 2 pressure1 1 27 double 0.5967368454 0.95115399245 0.08747213813 0.28749644837 0.40514625881 0.16690134756 0.62865801418 0.030783662473 0.73469688514 0.15982357526 0.94215501991 0.853981868 0.23819470223 0.95185671549 0.37963864995 0.060379164151 0.55299101432 0.40994903565 0.44752862897 0.94077520508 0.098657258377 0.61637721618 0.61373522457 0.76903310377 0.73321879947 0.54788850996 0.4664110617 METADATA INFORMATION 0 pressure2 1 27 double 0.5967368454 0.95115399245 0.08747213813 0.28749644837 0.40514625881 0.16690134756 0.62865801418 0.030783662473 0.73469688514 0.15982357526 0.94215501991 0.853981868 0.23819470223 0.95185671549 0.37963864995 0.060379164151 0.55299101432 0.40994903565 0.44752862897 0.94077520508 0.098657258377 0.61637721618 0.61373522457 0.76903310377 0.73321879947 0.54788850996 0.4664110617 METADATA INFORMATION 0 POINT_DATA 40 FIELD FieldData 2 temp1 1 40 double 0.70315056489 0.77283040507 0.23882065545 0.47826852144 0.2100912521 0.53921783206 0.20433042163 0.73420831075 0.027654148794 0.68639133094 0.4330220864 0.28495508317 0.33821187823 0.82527437165 0.54255032296 0.45393458559 0.83989136196 0.85876287932 0.4214370932 0.19047900181 0.51820664038 0.77471790134 0.60592653466 0.81065380638 0.62617898509 0.38810685582 0.1126304294 0.20460114912 0.54238177923 0.81393995793 0.96197048162 0.4422555548 0.2418563543 0.1052903392 0.48388728482 0.4595709923 0.20135841829 0.89066770205 0.34317565499 0.65652281351 METADATA INFORMATION 0 temp2 1 40 double 0.70315056489 0.77283040507 0.23882065545 0.47826852144 0.2100912521 0.53921783206 0.20433042163 0.73420831075 0.027654148794 0.68639133094 0.4330220864 0.28495508317 0.33821187823 0.82527437165 0.54255032296 0.45393458559 0.83989136196 0.85876287932 0.4214370932 0.19047900181 0.51820664038 0.77471790134 0.60592653466 0.81065380638 0.62617898509 0.38810685582 0.1126304294 0.20460114912 0.54238177923 0.81393995793 0.96197048162 0.4422555548 0.2418563543 0.1052903392 0.48388728482 0.4595709923 0.20135841829 0.89066770205 0.34317565499 0.65652281351 METADATA INFORMATION 0 tests/meshes/vtk/05_rectilinear.vtk000066400000000000000000000046171456244072500176640ustar00rootroot00000000000000# vtk DataFile Version 4.2 vtk output ASCII DATASET RECTILINEAR_GRID DIMENSIONS 10 1 4 X_COORDINATES 10 double 0 0.11111111111 0.22222222222 0.33333333333 0.44444444444 0.55555555556 0.66666666667 0.77777777778 0.88888888889 1 Y_COORDINATES 1 double 0 Z_COORDINATES 4 double 0 0.66666666667 1.3333333333 2 CELL_DATA 27 FIELD FieldData 2 pressure1 1 27 double 0.23241625202 0.11445560209 0.76365154653 0.47087525569 0.72431649469 0.92392403459 0.77855368618 0.84124534651 0.23006099738 0.072055527286 0.54402393208 0.76577680989 0.95543852626 0.5500200629 0.87894640567 0.1649442032 0.015127389286 0.91713330418 0.88199809591 0.67635433792 0.022145891361 0.27235031166 0.2517931659 0.23538443475 0.83078337459 0.12698638054 0.32136110723 METADATA INFORMATION 0 pressure2 1 27 double 0.23241625202 0.11445560209 0.76365154653 0.47087525569 0.72431649469 0.92392403459 0.77855368618 0.84124534651 0.23006099738 0.072055527286 0.54402393208 0.76577680989 0.95543852626 0.5500200629 0.87894640567 0.1649442032 0.015127389286 0.91713330418 0.88199809591 0.67635433792 0.022145891361 0.27235031166 0.2517931659 0.23538443475 0.83078337459 0.12698638054 0.32136110723 METADATA INFORMATION 0 POINT_DATA 40 FIELD FieldData 2 temp1 1 40 double 0.63326220102 0.65880449811 0.092134010247 0.26224177577 0.18028495303 0.45655723881 0.75424083555 0.25092637201 0.42578021015 0.34947513336 0.80900439304 0.10986986982 0.79435528494 0.040592168323 0.34699882279 0.64743497427 0.77190625479 0.87132637738 0.85488395442 0.68169002004 0.479460097 0.44164793037 0.42271564266 0.60839199607 0.16007533174 0.11289515092 0.72833184529 0.067663762988 0.86608996337 0.30484964892 0.96540154884 0.94371142461 0.14854998865 0.66201000286 0.29212325327 0.088839789059 0.94721379534 0.16104719752 0.21336087397 0.98095779109 METADATA INFORMATION 0 temp2 1 40 double 0.63326220102 0.65880449811 0.092134010247 0.26224177577 0.18028495303 0.45655723881 0.75424083555 0.25092637201 0.42578021015 0.34947513336 0.80900439304 0.10986986982 0.79435528494 0.040592168323 0.34699882279 0.64743497427 0.77190625479 0.87132637738 0.85488395442 0.68169002004 0.479460097 0.44164793037 0.42271564266 0.60839199607 0.16007533174 0.11289515092 0.72833184529 0.067663762988 0.86608996337 0.30484964892 0.96540154884 0.94371142461 0.14854998865 0.66201000286 0.29212325327 0.088839789059 0.94721379534 0.16104719752 0.21336087397 0.98095779109 METADATA INFORMATION 0 tests/meshes/vtk/06_color_scalars.vtk000066400000000000000000000005101456244072500201760ustar00rootroot00000000000000# vtk DataFile Version 2.0 data ASCII DATASET UNSTRUCTURED_GRID POINTS 5 float 1.5 0.0 0.0 0.0 1.5 0.0 1.5 1.5 0.0 0.0 0.0 0.0 -1.5 -1.5 0.0 CELLS 2 7 2 3 4 3 0 1 2 CELL_TYPES 2 3 5 POINT_DATA 5 COLOR_SCALARS lut 4 1.0 0.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 0.0 1.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 tests/meshes/vtk/06_unstructured.vtk000066400000000000000000000022611456244072500201240ustar00rootroot00000000000000# vtk DataFile Version 5.1 vtk output ASCII DATASET UNSTRUCTURED_GRID POINTS 42 float 1.3 0.8 0.4 1.4 0.8 0.4 1.4 0.9 0.4 1.3 0.9 0.4 1.3 0.8 0.5 1.4 0.8 0.5 1.4 0.9 0.5 1.3 0.9 0.5 1.5 0.8 0.4 1.5 0.9 0.4 1.5 0.8 0.5 1.5 0.9 0.5 1.3 0.9 0 1.4 0.9 0 1.4 1 0 1.3 1 0 1.3 0.9 0.1 1.4 0.9 0.1 1.4 1 0.1 1.3 1 0.1 1.3 0.9 0.2 1.4 0.9 0.2 1.4 1 0.2 1.3 1 0.2 1.3 0.9 0.3 1.4 0.9 0.3 1.4 1 0.3 1.3 1 0.3 1.4 1 0.4 1.3 1 0.4 1.4 1 0.5 1.3 1 0.5 1.5 0.9 0 1.5 1 0 1.5 0.9 0.1 1.5 1 0.1 1.5 0.9 0.2 1.5 1 0.2 1.5 0.9 0.3 1.5 1 0.3 1.5 1 0.4 1.5 1 0.5 CELLS 13 96 OFFSETS vtktypeint64 0 8 16 24 32 40 48 56 64 72 80 88 96 CONNECTIVITY vtktypeint64 0 1 2 3 4 5 6 7 1 8 9 2 5 10 11 6 12 13 14 15 16 17 18 19 16 17 18 19 20 21 22 23 20 21 22 23 24 25 26 27 24 25 26 27 3 2 28 29 3 2 28 29 7 6 30 31 13 32 33 14 17 34 35 18 17 34 35 18 21 36 37 22 21 36 37 22 25 38 39 26 25 38 39 26 2 9 40 28 2 9 40 28 6 11 41 30 CELL_TYPES 12 12 12 12 12 12 12 12 12 12 12 12 12 CELL_DATA 12 SCALARS mat_id int LOOKUP_TABLE default 2 2 1 1 1 1 2 1 1 1 1 2 POINT_DATA 42 SCALARS node_groups int LOOKUP_TABLE default 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 tests/meshes/vtk/gh-935.vtk000066400000000000000000000005461456244072500157700ustar00rootroot00000000000000# vtk DataFile Version 3.0 vtk output ASCII DATASET UNSTRUCTURED_GRID POINTS 6 float 0 1 0.0 0 0 0.0 1 0 0.0 0 1 0.0 1 0 0.0 1 1 0.0 CELLS 2 8 3 0 1 2 3 3 4 5 CELL_TYPES 2 5 5 CELL_DATA 2 POINT_DATA 6 SCALARS sol float 2 LOOKUP_TABLE default -1 1 -1 0 0 -0 0 0 0 0 0 0 tests/meshes/vtk/rbc_001.vtk000066400000000000000000001006171456244072500162020ustar00rootroot00000000000000# vtk DataFile Version 1.0 rbc_001.vtk 3D Unstructured Grid of Triangles ASCII DATASET UNSTRUCTURED_GRID POINTS 500 float -3.424999 -0.855454 2.257396 -1.484919 0.665606 -3.151304 1.636841 -0.848154 -0.458954 3.732041 0.187906 -1.319734 -1.756719 0.682006 0.807596 0.911641 -0.828054 3.040696 -0.218059 -0.489374 -3.806524 -1.078099 0.891706 -2.420454 -3.338019 0.263706 1.386896 2.931841 1.447006 1.793796 -1.796229 0.715706 1.214996 2.421641 1.454706 0.904796 -0.204659 0.658506 3.627796 -2.160579 -0.044274 3.331996 0.495541 -0.380754 -3.778464 0.053641 1.122906 -2.441584 -1.962639 -1.126464 3.026496 0.009941 1.061706 2.921296 0.252541 0.849906 0.570996 -1.675219 -1.336964 2.454096 0.409141 0.968806 -1.146214 2.016341 1.414006 -2.211994 -1.008069 -1.305914 1.804096 -2.530049 0.495106 2.133796 2.489541 0.835106 -3.168524 -1.025719 -1.208374 -2.156554 0.768841 -0.904814 -2.371244 3.327941 -0.212814 1.173396 -0.179759 0.895606 -1.223224 2.897641 -0.330874 -1.827444 0.013941 -0.720894 -3.509614 -1.960699 -1.392874 1.492296 -2.685229 0.550306 -0.706694 -2.297709 0.619406 0.586196 -3.521319 -0.083864 1.833196 -2.201219 -0.828584 -3.217494 -0.360359 -0.889074 3.534896 3.468741 -0.190594 0.697996 -0.013059 1.067406 -2.013034 -2.036049 0.250906 3.181796 -3.022249 0.471206 -0.260454 -3.295369 -0.809574 -2.371464 -1.521199 0.796606 2.329096 0.574041 -0.871424 -2.850944 1.364141 -0.949124 1.757796 -3.098809 -1.382564 1.671896 0.341441 -0.982094 -0.316984 3.380241 0.552906 2.256096 -1.214439 0.759306 -1.130544 1.671941 1.292106 -2.835764 2.491941 -0.394084 -2.298934 2.029841 -0.587094 -2.285774 -2.777879 -0.951204 -2.762034 0.566441 -0.961874 -1.878424 3.446041 0.698506 -2.345714 -3.547709 -0.450094 2.114896 -2.336589 0.629806 1.022096 0.848541 1.224606 2.076096 1.314241 1.287706 2.779996 -2.709559 -1.280744 -2.224514 3.367141 0.017976 -1.816064 3.232341 0.051706 2.114896 0.541141 -0.869594 3.255796 2.128541 -0.497124 2.652896 -0.200059 -1.053504 3.208996 -3.756499 0.066606 0.776996 -3.967359 -1.328364 -0.088464 -1.813299 0.726006 -1.791184 3.796541 1.269606 1.178996 1.059441 -0.933104 -0.369634 0.764641 -0.181114 3.786496 3.614641 0.458406 1.807496 0.174741 -1.149784 2.131896 1.279841 -0.896984 -0.835184 -0.483759 0.750706 -0.474934 1.634441 -0.617364 2.942196 1.827941 -0.867034 1.017696 3.867841 0.122106 0.346746 0.176841 1.027506 1.681196 2.225041 1.175706 2.845196 -2.500429 -1.389734 0.049896 -2.051029 0.619206 2.480296 -3.125099 -0.430314 2.663296 -0.736519 -1.247034 1.423396 1.188141 -0.197534 -3.677924 1.832341 -0.803304 1.991596 0.211041 1.027506 -1.579384 -3.254559 0.137506 -1.890674 -0.771749 0.856406 1.552396 4.013141 1.273606 0.476596 -2.140089 0.548706 -2.465164 -0.101059 0.185806 -4.007984 -2.145699 0.432206 2.838696 -0.124659 -1.003264 -2.836324 -3.656639 -1.327274 -1.205834 1.990941 0.889406 3.301896 -3.563009 -1.078494 -1.807824 3.114041 -0.382604 -0.930404 -2.629559 -1.438624 -1.052814 0.668341 -0.484874 3.660796 2.528741 1.352506 2.330696 3.056941 -0.458614 -0.045094 -2.171369 -1.329874 0.457096 -0.542059 -1.084944 -0.932734 -3.823749 -0.821974 1.650896 0.440041 -0.998044 -1.463874 -2.106999 0.624406 -0.558624 1.826441 0.404306 3.518896 3.806941 1.402606 -0.673144 -0.175859 -1.177544 1.418596 -0.430259 -0.984474 -3.124334 -1.429589 0.105206 -3.781744 2.318241 -0.226994 2.950596 0.988841 -0.551814 3.477596 -3.672659 0.131006 -0.855224 3.800141 0.181506 0.958096 -1.200429 0.745406 1.081696 -0.132059 1.001306 -3.235794 2.477541 1.434306 0.434786 1.191441 -0.736104 -2.760274 -4.140549 -0.733584 -0.846874 -3.094119 -1.123994 -2.225014 -3.149999 -0.062234 2.407796 -1.158149 -1.072274 -3.039524 -0.400659 -1.241414 1.903496 1.400641 -0.174024 3.597496 -1.630609 0.521006 3.115196 -1.910689 0.640406 0.362426 2.543641 -0.179114 -2.735614 1.308541 -0.967644 1.277396 -1.093769 -1.170714 -1.120094 -2.038329 0.620406 -0.058894 -3.683249 -0.062744 -1.421644 3.818441 0.036916 -0.292334 -0.993219 -0.522244 3.780696 -2.148329 -1.325934 -2.178484 2.447041 1.396806 -0.113854 -3.777879 -1.387444 0.533296 -0.112359 -1.087874 0.573196 1.377841 1.272306 1.635396 1.254941 0.151606 3.713996 0.372641 -1.007944 -1.036354 0.403441 1.165806 2.515396 1.230641 -0.844674 2.678496 3.348241 0.265006 -2.227234 -2.340539 0.614206 -1.496794 2.706141 1.026906 2.803596 -1.531129 0.802406 1.941896 0.804641 1.121306 -1.501914 0.059541 0.809706 -0.311584 1.451341 -0.739234 -2.431744 0.343741 0.558806 -3.900584 -2.072989 0.334706 -3.202074 -1.751489 -1.001144 -3.138244 2.893641 0.571106 -2.934174 1.919241 1.291906 0.708896 -3.474459 -1.394114 1.127496 0.477941 0.873206 -3.684324 1.020041 0.816806 -3.717124 -1.097129 -1.220604 1.032496 -3.003429 -1.491814 0.041216 -0.507559 -0.220114 -3.970844 -0.871339 0.908506 -1.824914 -1.002469 0.877506 -2.880294 -4.003789 -0.252654 -0.874304 1.928341 -0.505854 -2.700694 -4.185099 -0.475784 -0.280294 2.133041 1.318306 -0.575044 -1.046039 0.694406 3.191796 -3.890309 -1.158434 1.104596 2.113641 1.121406 -3.070624 -2.010099 -1.292954 -0.216314 1.987941 -0.788144 -0.140574 -1.267489 0.847406 -2.042934 1.081541 -0.900484 -1.586604 1.738041 -0.756064 2.435396 -0.069359 0.820406 0.927096 -0.635559 0.800206 1.127196 2.931141 0.143506 2.623996 -4.225549 -0.669494 0.371026 -0.338759 0.966206 -1.677904 3.366541 -0.280934 -0.452624 -1.410509 -1.305514 1.425996 0.167541 1.102406 2.105496 -2.300829 0.579706 -1.995564 1.544641 -0.527864 -2.984594 -1.480049 -1.367304 2.012496 1.878641 -0.009994 -3.437454 -1.177279 -1.306154 2.668896 -0.553259 -1.221724 2.822196 1.621241 1.165206 -0.259554 0.955141 -0.677624 -3.163504 0.479541 1.086106 -3.276734 1.177041 -0.857644 -2.034864 -2.630079 -0.422604 3.087996 3.196841 -0.183384 1.661096 -0.283959 -1.216724 2.424996 -0.107759 -1.058054 -1.231574 2.249141 1.312206 -2.593074 0.830641 -1.040704 1.520796 0.576841 -1.023904 0.578496 1.423641 1.337406 -2.343334 -0.730489 0.730806 0.734796 0.769941 0.229206 3.836296 4.100741 1.182206 -0.238214 2.089241 0.092906 3.337096 -0.763159 0.136706 -3.966944 2.048641 -0.227544 -3.081924 -3.669929 0.168106 0.252466 0.140141 -1.084624 2.934796 0.851241 0.607406 3.712096 3.700541 0.473606 -1.803374 -2.468259 -0.464164 -3.254234 -0.203359 0.903606 1.386696 -0.643559 -0.829614 -3.468714 1.614941 1.173406 0.307636 1.392641 0.580206 3.626796 -2.505129 0.283706 -2.756974 0.253041 -1.109694 2.506596 3.828141 0.886106 -1.663004 1.044541 1.128806 -3.297774 0.181941 0.250406 3.905496 1.562941 1.190006 -0.810124 0.781841 -1.043654 1.933696 -3.185429 0.424706 0.220286 -3.531809 -1.195284 1.705096 -2.097159 -1.340254 -0.863994 -1.135099 -1.219464 -1.635044 -0.228059 0.551806 -3.881094 -1.908889 -0.349964 -3.592664 0.218941 -0.982404 -2.523044 0.260041 -0.803284 3.486996 -3.861169 -0.444074 1.489996 2.300241 -0.574664 2.219096 0.152141 -1.099804 0.946196 3.145741 -0.413984 0.443116 3.507441 -0.195284 0.108416 1.944941 1.339006 -1.191414 0.712741 1.140906 1.651796 -2.285379 -1.159364 -2.725134 1.321641 0.496906 -3.766264 -0.113859 0.838606 -3.632624 2.832541 -0.493464 1.442796 -1.841069 0.723306 1.646096 -0.459359 1.016406 2.225996 0.201841 -1.017674 0.189156 -2.841829 0.421906 -1.719214 0.231941 -0.095884 -3.976554 2.697141 1.501506 1.322996 -1.631849 -0.014764 3.592596 4.061241 0.948106 0.957796 1.418341 -0.368324 -3.372364 2.487241 1.436906 -1.049184 2.995641 1.236706 2.259996 2.362241 -0.658334 1.734596 -1.561139 -1.230494 2.969396 1.554241 1.240906 1.116496 2.133941 -0.699834 -1.353124 0.626741 0.939306 0.855396 -2.521189 0.573706 -0.265734 -3.175499 -1.467974 -1.143624 -2.036329 -0.890544 3.291296 0.962641 1.060106 -0.985534 -1.670869 0.685006 -0.876284 -1.524279 0.747106 -2.679794 1.228941 -0.958444 0.811796 2.037241 1.395306 1.342896 1.108541 1.029206 -0.500484 -2.722179 -1.445594 0.558096 1.703441 1.345006 -1.781734 -2.143929 -1.295104 2.540596 -1.302389 -1.200624 0.643196 1.449241 -0.890044 0.039516 -0.215759 0.355906 3.842396 -0.920159 -1.124644 3.251996 0.225241 -1.137294 1.749496 -0.786199 -1.095824 -0.176074 -1.303999 0.689606 0.573696 2.387341 -0.695494 1.207696 3.616041 -0.063804 -0.868164 1.275241 -0.915394 2.204296 1.104941 1.255006 -1.907854 -2.126609 0.680406 1.985496 -0.612959 -1.130234 -1.434614 0.288041 -0.826834 -3.206864 1.504641 1.081106 -3.301794 0.956941 1.083106 3.279996 3.425541 1.292006 1.749896 -1.562639 0.657506 -0.367044 -0.385059 0.723606 0.010976 0.643941 0.357306 -3.944714 1.143541 1.026006 0.066126 -3.923099 -0.495494 -1.432014 2.303941 1.442606 -1.648764 2.674241 -0.622824 0.391136 -2.575289 0.574706 0.181276 2.102141 -0.780244 0.270976 2.378241 1.455306 1.844496 -1.409929 -0.961854 3.454296 4.013241 0.332406 -0.723214 -1.573919 -1.215954 -0.711444 3.366141 1.546806 0.229086 3.014341 1.508506 -0.892014 -2.636479 -1.351154 2.158996 0.922241 0.047476 -3.878244 0.762741 -1.012504 2.373096 -3.926779 -0.052834 -0.307064 2.968041 0.646406 2.733196 3.782941 1.456006 -0.006234 0.293941 0.980106 3.322096 0.743841 0.927906 0.369276 0.353641 -1.106064 1.342896 0.550941 0.926506 -0.651724 1.762441 0.858206 -3.461724 0.785441 -0.965424 0.039136 -2.446739 -0.783074 3.110596 -1.761889 -1.299734 0.946196 -2.697899 -0.063044 -3.002244 0.640841 -0.980814 2.763096 -1.050859 -1.134324 0.211156 3.911441 0.552606 1.280196 3.353541 1.548406 -0.400284 -0.360759 0.853606 3.253696 -0.389559 -1.095464 -2.375984 -2.230669 0.634006 -1.033524 -0.163959 -1.039024 -0.132964 1.953141 1.367106 2.454696 3.068341 1.251806 -2.229364 0.992941 1.103506 1.196096 -0.354459 -1.058014 -0.495984 -2.665739 0.304606 2.489996 -0.427759 -1.081724 0.236916 3.759441 0.923206 1.707396 2.993841 1.552106 0.718696 2.296441 -0.743554 0.741996 -1.763279 -1.196994 -2.678954 3.417241 1.480306 -1.070794 1.431641 1.326906 2.206896 -2.096879 -1.401974 2.006296 -3.095769 -1.187684 2.249096 -4.128129 -1.086374 0.486896 0.675741 -0.955924 -0.695564 -1.630539 -1.295414 -1.868474 -0.768859 0.565106 3.506796 4.012841 0.625006 -1.187824 -1.592159 -0.658304 -3.554044 -2.151139 -1.366284 -1.505324 1.944341 0.534006 -3.505884 2.740341 1.467306 -0.486764 -1.790669 0.713506 -1.313474 -2.856189 0.495806 1.193596 -0.925189 0.930706 2.507296 -1.699529 0.733406 -2.239544 4.207241 0.885506 0.224376 -0.837619 0.695306 0.283396 0.104841 -1.031214 -2.123114 -2.548549 -1.424364 1.589096 -0.612259 0.793806 -0.936894 1.131341 -0.948084 0.398946 -2.658279 -1.417134 -1.649294 0.653841 1.171006 2.953596 -4.042969 -0.364854 0.835896 -3.526489 -1.494984 -0.025274 2.868441 1.487406 -1.434434 2.522341 0.143006 -3.086934 3.510241 1.089206 -2.010794 2.655341 1.425806 -2.070284 0.943541 1.250306 2.522996 2.051841 1.298306 0.066136 -4.223849 -0.936654 -0.173444 0.290641 -0.136404 3.874196 -1.223659 -0.271774 -3.852484 2.581841 0.234906 2.999296 2.808341 -0.374994 1.972596 -2.557319 -1.120344 2.757496 -3.287539 -1.493654 0.579396 -0.594659 -0.048564 3.911296 2.679541 -0.253214 2.470396 3.700541 1.267106 -1.359364 -0.959359 0.694006 -0.198754 4.180941 0.748706 -0.471614 2.535541 -0.659604 -0.082264 -3.089509 0.229006 1.982496 1.731841 -0.727054 -2.039894 0.752941 1.246206 -2.426534 -2.794649 0.507006 -1.181084 -3.928009 -0.950514 -1.345824 -1.636959 -1.274204 -1.269404 -1.940279 0.529306 -2.870564 1.882741 -0.848684 1.494496 -3.549919 -0.243094 -2.000504 -0.985279 0.894306 2.008496 -0.019559 0.850306 -0.771854 -4.049549 -0.204584 0.297226 4.087041 0.536406 0.624496 0.371741 0.972006 1.250196 -3.046759 0.034546 -2.443624 -0.719569 -1.137034 0.634596 -3.158539 -1.349784 -1.706094 -0.279059 0.747106 0.458496 -1.316909 0.801306 -1.568304 2.739641 -0.508704 -1.402154 4.125641 0.432706 -0.049424 -2.650109 0.030536 2.922696 0.728641 -0.572354 -3.501974 -3.251199 -0.368214 -2.488764 -1.667539 -1.229094 0.297986 -3.511899 0.271306 -0.265254 -1.217199 -0.839184 -3.421624 1.688541 -0.870954 0.546196 -2.974609 -0.856614 2.734296 -0.895229 -0.556384 -3.761854 2.268441 -0.709414 -0.535614 -1.094129 0.717706 -0.654994 -0.452859 -1.158414 1.013596 -1.450159 0.338706 3.469996 -4.085079 -0.786084 1.017296 -2.013369 -0.428744 3.485496 0.186241 0.812206 0.140706 3.297341 0.979906 2.281496 -1.587119 -0.584934 3.599196 3.576841 0.144706 1.499496 2.837841 -0.528204 -0.495564 1.889941 -0.783134 -0.895424 -1.428079 0.758706 2.798596 0.046441 -0.556934 3.784296 -3.684669 -0.679584 -1.936454 -0.686599 0.914906 2.917896 -0.347959 1.019106 -2.897304 -0.755329 0.847706 -1.379134 3.290941 -0.199454 -1.362574 -1.419229 0.659306 0.105926 -1.311779 0.798806 1.546596 1.666841 1.197906 3.029896 -2.321029 0.633806 1.482596 3.287141 1.490906 1.234996 2.984741 -0.097804 -2.290484 -2.836459 0.532306 0.656296 -0.861149 -1.306774 2.294096 -0.311359 -0.327694 3.905596 -3.734009 -0.074834 1.271696 1.872541 1.382106 1.877196 -1.407059 -1.176224 -0.210924 -2.367179 -1.400034 1.022796 1.364841 1.219006 -1.359284 1.681541 -0.782554 -1.677954 -0.059659 -1.061814 -1.689014 2.290341 0.381006 -3.348324 0.475541 0.734206 3.681596 -4.023649 -1.188844 -0.711754 -0.577459 1.001106 -2.162764 1.243741 1.071406 0.684396 2.914741 -0.510524 0.930496 0.902341 -0.944574 -1.144034 -0.839749 0.521606 -3.775084 4.048341 1.041606 -0.934924 -0.546859 1.000206 -2.571354 1.303541 0.921306 3.446996 2.932241 1.521106 0.098186 2.429641 0.627306 3.172496 2.306841 -0.595294 -1.818344 -0.992569 -1.123874 -0.610844 1.003941 1.263606 -2.859874 3.594241 1.493206 0.682696 -3.338079 0.342506 0.779696 3.029841 0.258606 -2.684064 2.654641 1.184106 -2.680514 -0.231759 1.062706 2.546896 -0.821239 -1.130474 -2.681534 -1.402569 0.509406 -3.546474 -1.452419 -1.244514 -2.433904 -0.661849 0.763206 -3.535814 -3.107039 -1.510414 -0.552684 1.605141 0.186106 -3.659124 -3.223199 0.382406 -0.773184 3.076441 0.948906 -2.630754 -2.743569 0.480606 1.693896 -2.588259 -1.436754 -0.474874 -3.638209 -1.458764 -0.615664 -2.727689 0.347506 -2.256804 0.030141 -1.025324 -0.732464 -1.283989 -0.180894 3.756196 -3.285119 0.273906 -1.328174 -0.357559 0.968406 1.837296 -2.064339 0.056406 -3.468924 -0.845689 0.842506 -3.252574 1.527441 -0.844614 -1.273824 -0.703919 -0.773084 3.688796 2.527141 -0.614204 -0.945414 -0.561259 -1.137704 -1.919154 1.234441 -0.629994 3.225896 3.253041 1.394206 -1.693584 0.767641 -1.038624 1.048796 0.639041 0.907006 -0.173444 -2.963859 -1.458584 1.104196 1.736241 -0.330294 3.299396 -0.916819 0.269506 3.752496 -2.924189 -0.517674 -2.831784 0.530241 1.155206 -1.994664 0.333941 1.167606 -2.848074 CELLS 996 3984 3 270 374 303 3 104 55 232 3 339 225 45 3 410 374 315 3 104 232 416 3 232 55 34 3 330 122 403 3 410 82 0 3 55 0 82 3 481 417 420 3 339 45 303 3 339 303 374 3 416 232 361 3 122 34 55 3 34 122 382 3 169 225 104 3 104 416 169 3 330 403 92 3 315 194 410 3 16 261 374 3 417 315 261 3 270 16 374 3 19 270 338 3 420 261 298 3 261 420 417 3 440 65 361 3 440 361 232 3 232 34 440 3 92 81 330 3 45 494 356 3 356 303 45 3 338 303 356 3 268 494 375 3 361 393 179 3 225 169 156 3 375 494 156 3 156 45 225 3 156 494 45 3 340 169 416 3 82 403 122 3 82 410 194 3 194 315 417 3 481 249 417 3 194 13 403 3 403 82 194 3 34 8 440 3 393 361 65 3 23 330 81 3 443 356 494 3 494 268 443 3 306 166 393 3 375 156 137 3 137 156 169 3 169 340 137 3 303 338 270 3 65 440 8 3 23 382 330 3 122 330 382 3 23 81 282 3 81 92 424 3 415 126 39 3 39 92 403 3 375 137 362 3 338 356 31 3 356 443 31 3 268 80 102 3 102 443 268 3 66 340 369 3 340 416 179 3 361 179 416 3 166 179 393 3 19 186 188 3 476 382 23 3 23 282 476 3 434 350 476 3 476 282 434 3 126 168 424 3 42 282 81 3 12 343 496 3 92 39 126 3 343 168 415 3 343 12 322 3 179 369 340 3 66 137 340 3 66 362 137 3 478 66 449 3 338 186 19 3 316 182 31 3 438 188 186 3 338 31 186 3 182 22 186 3 438 186 22 3 316 31 443 3 443 102 316 3 186 31 182 3 159 182 316 3 406 102 171 3 375 362 160 3 160 268 375 3 160 80 268 3 40 32 474 3 32 40 259 3 306 407 114 3 96 94 386 3 438 124 196 3 427 467 351 3 295 259 40 3 106 32 259 3 259 295 131 3 324 32 106 3 288 431 379 3 56 350 434 3 434 10 56 3 56 4 33 3 127 33 4 3 437 464 350 3 437 33 295 3 350 56 437 3 437 56 33 3 208 306 393 3 208 407 306 3 393 65 208 3 65 464 208 3 382 476 8 3 382 8 34 3 8 464 65 3 350 464 8 3 8 476 350 3 126 415 168 3 427 351 424 3 126 424 92 3 427 424 168 3 362 66 478 3 449 94 478 3 369 449 66 3 397 319 331 3 102 406 316 3 159 316 271 3 271 316 406 3 442 319 406 3 319 397 271 3 159 271 397 3 30 404 284 3 53 26 193 3 43 119 26 3 224 40 407 3 407 208 224 3 224 208 464 3 295 40 224 3 224 437 295 3 464 437 224 3 166 306 164 3 306 114 164 3 121 41 52 3 41 121 96 3 449 386 94 3 386 449 120 3 420 134 481 3 420 298 134 3 322 17 427 3 142 183 467 3 391 351 244 3 42 424 351 3 81 424 42 3 114 132 164 3 292 164 132 3 263 324 106 3 106 288 263 3 32 324 385 3 145 385 324 3 184 246 145 3 385 145 246 3 259 131 106 3 288 106 131 3 131 295 127 3 33 127 295 3 127 431 131 3 431 288 131 3 184 90 479 3 352 264 90 3 249 496 415 3 376 496 481 3 39 13 415 3 249 481 496 3 39 403 13 3 249 415 13 3 194 417 13 3 13 417 249 3 376 481 134 3 230 43 26 3 185 191 251 3 191 284 404 3 119 191 185 3 119 165 150 3 207 185 251 3 191 119 43 3 472 160 362 3 362 478 472 3 94 96 398 3 398 96 121 3 426 292 390 3 390 132 87 3 386 120 292 3 164 292 120 3 369 120 449 3 166 164 120 3 120 369 166 3 179 166 369 3 16 255 298 3 315 374 261 3 16 270 255 3 19 255 270 3 193 150 383 3 276 331 319 3 159 397 414 3 414 397 138 3 331 138 397 3 275 199 223 3 124 275 72 3 172 2 412 3 196 72 218 3 72 196 124 3 196 189 438 3 188 438 189 3 218 209 196 3 64 189 209 3 17 309 360 3 286 360 309 3 147 42 391 3 88 432 391 3 18 399 176 3 18 176 258 3 116 432 88 3 429 400 48 3 379 289 74 3 57 238 183 3 78 483 183 3 142 467 17 3 244 467 183 3 78 183 238 3 183 142 57 3 441 266 139 3 118 155 11 3 11 155 266 3 238 57 139 3 256 139 266 3 215 451 155 3 213 395 176 3 238 395 78 3 213 78 395 3 483 78 213 3 212 229 35 3 317 484 212 3 405 317 497 3 132 482 87 3 474 482 114 3 284 110 30 3 93 284 43 3 471 454 469 3 229 111 371 3 1 485 469 3 264 163 1 3 184 479 246 3 246 87 482 3 87 246 479 3 479 90 217 3 485 1 163 3 111 469 454 3 485 117 471 3 60 436 144 3 29 436 60 3 324 263 349 3 48 400 349 3 349 263 48 3 413 288 379 3 413 263 288 3 48 263 413 3 379 74 413 3 163 7 456 3 487 134 298 3 425 439 487 3 134 487 439 3 185 165 119 3 51 150 165 3 383 150 51 3 319 442 276 3 80 171 102 3 94 398 260 3 260 478 94 3 260 472 478 3 132 390 292 3 426 386 292 3 426 41 96 3 96 386 426 3 405 390 396 3 497 41 405 3 212 497 317 3 390 405 426 3 41 426 405 3 405 396 317 3 87 396 390 3 305 223 280 3 453 174 486 3 257 423 486 3 311 199 275 3 138 331 245 3 36 64 231 3 318 5 209 3 209 62 64 3 36 274 64 3 318 209 218 3 318 218 305 3 218 72 305 3 17 360 142 3 367 142 360 3 367 57 142 3 63 233 377 3 42 147 282 3 434 282 243 3 243 282 147 3 243 147 432 3 243 10 434 3 243 432 10 3 391 244 483 3 183 483 244 3 244 351 467 3 351 391 42 3 391 483 88 3 147 391 432 3 418 289 399 3 399 18 418 3 418 18 310 3 277 431 127 3 177 116 88 3 177 213 176 3 177 88 213 3 483 213 88 3 162 429 180 3 256 451 328 3 328 395 238 3 238 139 328 3 328 139 256 3 395 258 176 3 395 328 258 3 258 328 451 3 310 18 258 3 258 451 310 3 132 114 482 3 474 114 407 3 474 385 482 3 246 482 385 3 385 474 32 3 407 40 474 3 497 212 52 3 497 52 41 3 24 475 154 3 154 54 465 3 285 313 158 3 157 158 151 3 206 371 111 3 111 484 469 3 152 469 484 3 228 454 241 3 471 469 485 3 152 484 317 3 217 388 152 3 396 217 317 3 67 145 349 3 324 349 145 3 67 352 184 3 145 67 184 3 67 349 400 3 48 413 357 3 357 413 74 3 357 429 48 3 28 429 357 3 163 264 7 3 352 7 264 3 117 485 428 3 388 90 264 3 400 429 162 3 28 180 429 3 162 450 173 3 162 180 450 3 415 496 343 3 231 425 36 3 203 370 70 3 376 134 439 3 439 425 370 3 490 113 62 3 16 298 261 3 36 487 274 3 189 274 188 3 188 255 19 3 50 29 460 3 383 51 460 3 461 276 442 3 300 461 442 3 442 171 300 3 271 406 319 3 406 171 442 3 276 461 329 3 359 260 398 3 342 346 135 3 472 260 98 3 98 359 346 3 260 359 98 3 1 152 388 3 388 217 90 3 469 152 1 3 152 317 217 3 217 396 479 3 87 479 396 3 223 305 72 3 242 373 254 3 143 5 318 3 423 2 73 3 73 486 423 3 453 486 73 3 73 341 453 3 73 2 69 3 69 341 73 3 257 486 445 3 193 383 445 3 445 174 193 3 445 486 174 3 159 414 83 3 83 182 159 3 83 22 182 3 325 245 331 3 245 200 138 3 234 138 200 3 487 36 425 3 189 196 209 3 298 274 487 3 274 298 255 3 189 64 274 3 255 188 274 3 57 337 139 3 367 337 57 3 441 139 337 3 140 216 203 3 216 140 107 3 75 175 63 3 58 286 433 3 337 367 58 3 448 210 457 3 216 457 210 3 79 95 146 3 372 459 205 3 457 216 95 3 149 74 289 3 289 418 149 3 202 277 116 3 176 399 202 3 202 177 176 3 116 177 202 3 354 289 379 3 399 289 354 3 379 431 354 3 431 277 354 3 354 202 399 3 277 202 354 3 10 4 56 3 4 277 127 3 4 10 116 3 432 116 10 3 116 277 4 3 368 155 118 3 144 436 465 3 447 154 364 3 313 347 240 3 151 158 290 3 388 264 1 3 173 450 7 3 456 428 163 3 428 499 117 3 499 428 15 3 285 220 49 3 456 15 428 3 499 462 192 3 220 192 462 3 471 241 454 3 157 241 192 3 97 401 430 3 29 60 430 3 133 236 181 3 133 181 279 3 173 67 400 3 90 184 352 3 400 162 173 3 456 7 450 3 173 352 67 3 7 352 173 3 370 221 439 3 168 343 322 3 210 448 221 3 273 221 448 3 427 168 322 3 99 425 231 3 231 113 99 3 62 231 64 3 70 99 125 3 495 125 113 3 370 203 221 3 99 70 425 3 210 221 203 3 113 125 99 3 5 490 62 3 231 62 113 3 125 140 70 3 205 107 125 3 490 495 113 3 128 436 50 3 29 50 436 3 364 128 207 3 128 50 165 3 103 329 461 3 331 276 325 3 329 325 276 3 325 329 46 3 105 174 453 3 130 461 300 3 130 103 461 3 411 214 408 3 411 6 214 3 30 214 6 3 214 30 110 3 239 59 52 3 239 135 59 3 135 359 59 3 121 52 59 3 359 398 59 3 121 59 398 3 52 35 239 3 153 239 35 3 35 52 212 3 408 153 345 3 345 35 229 3 35 345 153 3 472 98 477 3 160 472 477 3 80 160 477 3 477 171 80 3 300 171 226 3 226 98 346 3 171 477 226 3 226 477 98 3 492 129 199 3 199 311 492 3 492 234 200 3 311 234 492 3 389 129 76 3 280 44 85 3 85 254 233 3 199 129 44 3 199 44 223 3 44 280 223 3 44 129 389 3 254 85 389 3 389 85 44 3 294 296 381 3 69 2 272 3 69 272 314 3 272 2 172 3 172 296 272 3 272 296 409 3 409 358 272 3 257 488 423 3 423 412 2 3 412 423 488 3 412 488 422 3 412 381 172 3 422 381 412 3 50 460 51 3 488 257 401 3 401 460 29 3 460 401 257 3 257 445 460 3 383 460 445 3 109 414 234 3 109 83 414 3 138 234 414 3 109 234 311 3 46 245 325 3 480 46 329 3 46 341 69 3 480 341 46 3 360 58 367 3 210 203 216 3 360 286 58 3 459 95 107 3 457 433 286 3 95 433 457 3 203 70 140 3 216 107 95 3 373 377 233 3 493 418 310 3 493 149 418 3 20 86 28 3 256 266 155 3 326 297 441 3 297 248 266 3 11 266 248 3 433 95 79 3 459 146 95 3 368 118 136 3 190 368 167 3 256 155 451 3 155 368 215 3 310 451 291 3 215 368 190 3 222 237 444 3 444 237 269 3 366 21 293 3 293 269 237 3 364 465 128 3 436 128 465 3 51 165 50 3 347 24 447 3 447 473 347 3 290 240 304 3 304 247 290 3 151 228 157 3 241 157 228 3 192 117 499 3 241 471 117 3 158 157 220 3 285 158 220 3 117 192 241 3 163 428 485 3 484 111 229 3 411 345 371 3 408 345 411 3 484 229 212 3 435 248 9 3 422 488 97 3 279 181 97 3 97 488 401 3 422 97 181 3 29 430 401 3 97 430 279 3 3 430 60 3 279 430 3 3 376 273 496 3 17 322 309 3 467 427 17 3 221 273 376 3 309 12 448 3 322 12 309 3 70 370 425 3 12 496 273 3 376 439 221 3 273 448 12 3 286 448 457 3 309 448 286 3 193 174 53 3 150 193 26 3 105 53 174 3 197 480 103 3 329 103 480 3 387 130 300 3 387 226 346 3 300 226 387 3 93 468 110 3 110 123 214 3 153 408 123 3 408 214 123 3 229 371 345 3 6 411 161 3 93 110 284 3 278 254 389 3 334 278 76 3 265 76 129 3 200 358 265 3 265 358 409 3 409 76 265 3 265 492 200 3 129 492 265 3 143 280 175 3 62 209 5 3 318 305 143 3 280 143 305 3 236 133 77 3 77 37 236 3 124 109 275 3 22 124 438 3 22 83 124 3 223 72 275 3 311 275 109 3 83 109 124 3 245 46 314 3 314 358 200 3 200 245 314 3 358 314 272 3 314 46 69 3 146 459 307 3 107 205 459 3 112 205 495 3 140 125 107 3 495 490 75 3 495 75 112 3 195 421 61 3 178 377 61 3 180 28 86 3 148 86 20 3 498 38 86 3 38 450 180 3 456 450 15 3 38 15 450 3 54 154 475 3 144 465 54 3 466 24 170 3 154 447 24 3 365 475 327 3 313 170 24 3 198 466 170 3 347 313 24 3 240 158 313 3 473 304 240 3 180 86 38 3 281 498 148 3 384 15 498 3 38 498 15 3 49 170 285 3 79 326 433 3 337 58 326 3 441 337 326 3 266 441 297 3 58 433 326 3 100 326 79 3 297 326 100 3 9 100 253 3 100 9 297 3 248 297 9 3 252 293 237 3 136 167 368 3 167 222 190 3 237 222 167 3 167 252 237 3 291 215 190 3 222 267 190 3 291 493 310 3 215 291 451 3 267 312 493 3 281 269 201 3 498 281 384 3 86 148 498 3 269 281 444 3 148 444 281 3 302 336 363 3 363 491 366 3 363 252 302 3 293 252 363 3 465 364 154 3 473 447 187 3 240 347 473 3 206 454 228 3 161 91 247 3 91 151 290 3 206 228 91 3 14 404 30 3 161 206 91 3 30 6 14 3 371 206 161 3 14 6 247 3 247 304 14 3 151 91 228 3 111 454 206 3 371 161 411 3 419 332 287 3 458 136 118 3 333 11 248 3 248 435 333 3 118 11 333 3 333 458 118 3 68 332 250 3 250 89 68 3 250 353 89 3 204 89 353 3 68 89 463 3 54 219 211 3 211 144 54 3 211 60 144 3 211 3 60 3 299 133 279 3 279 3 299 3 480 197 141 3 141 341 480 3 453 341 141 3 141 105 453 3 130 387 227 3 335 123 470 3 123 110 468 3 470 468 25 3 233 254 373 3 254 278 242 3 172 381 296 3 334 76 409 3 389 76 278 3 409 296 334 3 296 294 334 3 280 85 175 3 233 175 85 3 233 63 175 3 175 75 143 3 5 75 490 3 5 143 75 3 37 115 27 3 37 77 115 3 77 394 115 3 71 421 320 3 205 112 372 3 63 112 75 3 125 495 205 3 178 372 112 3 178 112 377 3 63 377 112 3 327 491 365 3 466 327 475 3 54 475 365 3 365 219 54 3 198 170 49 3 475 24 466 3 49 462 201 3 21 201 269 3 201 384 281 3 201 21 49 3 198 49 21 3 462 49 220 3 313 285 170 3 384 201 462 3 192 220 157 3 15 384 499 3 462 499 384 3 262 222 444 3 20 312 262 3 444 148 262 3 148 20 262 3 291 190 267 3 222 262 267 3 267 262 312 3 493 291 267 3 149 493 312 3 149 312 392 3 392 357 74 3 74 149 392 3 20 28 392 3 357 392 28 3 392 312 20 3 269 293 21 3 293 363 366 3 327 366 491 3 198 366 466 3 327 466 366 3 21 366 198 3 91 290 247 3 304 473 84 3 372 307 459 3 47 307 178 3 68 287 332 3 287 435 9 3 287 68 435 3 463 435 68 3 136 458 348 3 252 167 348 3 136 348 167 3 302 252 348 3 108 204 455 3 89 204 308 3 458 333 301 3 301 333 463 3 435 463 333 3 3 211 344 3 344 299 3 3 344 219 455 3 344 211 219 3 130 227 283 3 197 103 283 3 130 283 103 3 346 342 387 3 359 135 346 3 227 387 342 3 468 93 323 3 150 26 119 3 230 26 355 3 27 195 242 3 377 373 61 3 71 61 421 3 195 61 373 3 101 294 381 3 181 101 422 3 101 181 236 3 381 422 101 3 452 334 294 3 452 242 278 3 278 334 452 3 299 344 380 3 380 344 455 3 380 204 353 3 455 204 380 3 133 299 402 3 402 77 133 3 402 394 77 3 299 380 402 3 353 394 402 3 402 380 353 3 320 332 71 3 115 320 421 3 320 115 394 3 320 250 332 3 353 250 394 3 320 394 250 3 378 365 491 3 378 108 455 3 455 219 378 3 219 365 378 3 187 251 84 3 364 187 447 3 404 251 191 3 165 207 128 3 191 43 284 3 14 84 404 3 251 187 207 3 165 185 207 3 372 178 307 3 419 307 47 3 47 61 71 3 178 61 47 3 71 332 47 3 332 419 47 3 307 419 146 3 419 287 253 3 9 253 287 3 253 100 146 3 79 146 100 3 253 146 419 3 108 308 204 3 301 463 308 3 89 308 463 3 355 53 446 3 53 355 26 3 227 342 25 3 242 452 27 3 373 242 195 3 421 27 115 3 421 195 27 3 294 101 235 3 235 452 294 3 236 37 235 3 235 101 236 3 235 37 452 3 27 452 37 3 187 84 473 3 251 404 84 3 240 290 158 3 364 207 187 3 84 14 304 3 161 247 6 3 301 308 321 3 302 348 321 3 321 348 458 3 458 301 321 3 308 108 321 3 336 378 491 3 108 378 336 3 336 321 108 3 491 363 336 3 302 321 336 3 141 197 105 3 105 446 53 3 446 105 197 3 283 446 197 3 489 283 227 3 227 25 489 3 489 446 283 3 355 446 489 3 43 230 93 3 25 323 489 3 323 25 468 3 230 355 323 3 230 323 93 3 355 489 323 3 335 470 135 3 342 135 470 3 25 342 470 3 153 123 335 3 335 135 239 3 239 153 335 3 468 470 123 3 122 55 82 3 225 0 104 3 55 104 0 3 0 225 339 3 0 339 410 3 374 410 339 CELL_TYPES 996 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 tests/meshes/vtu/000077500000000000000000000000001456244072500143335ustar00rootroot00000000000000tests/meshes/vtu/00_raw_binary.vtu000066400000000000000000000162341456244072500175350ustar00rootroot00000000000000 _UUUUUU?UUUUUU???UUUUUU??UUUUUU????UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU??UUUUUU??UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU??UUUUUU??UUUUUU?UUUUUU??UUUUUU???UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU????UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU???UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU???UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU??UUUUUU????UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU????UUUUUU?UUUUUU???UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU??UUUUUU??UUUUUU?UUUUUU?UUUUUU??UUUUUU??UUUUUU??                                          ! "  #$  ! "  % &! !#"'(##'$)! !%"*+ % %* &,!-!(!##'"'.#(#)#'/$)/!-!+!%%*"*.%+ %, %*0 &,0!(-!#(!#1#'.#()#)/#'/2$)/3!+-!%+!%1%*.%+, %,0%*04&,05!(-6!#(1#.1#'.2#()7#)/2)/38!+-6!%+1%.1%*.4%+,9%,04,05:!(16#(17#.12#)27)/28!+16%+19%.14%,49,04:(167#127.12;)278+169%149.14;,49:167<127;278=169<149;49:>17;<27;=19;<49;>7;<=9;<>;<=?;<>?  $(,048<@DHLPTX\`dhlptx|  $(,048<@DHLPTX\`dhlptx|  $(,048<@DHLPTX\`dhlptx| &#dU?EDPB>M?( Zx 1>/~?G?&nV=? uL>m?h ? =^=?( ?`4 7>n?hm ?]=?*x=?2Gp&0>ya?r1?yoZ=?P?W=?P)/0>W:?e?O?W=?Pϡ,2>vϊ?(-4Б>x?1x?[s%?8?&X=?깫?W=?5?&lX=?i? ޲W=?FH?_ldx?3 %?p?[[=?(x?" %?:?M[=?_y? %?rf,;W=? y? %?j?<9T?[(J?T?(J?x̑T?n(J?w?oL %?*T?(J?dT? (J?T? (J?5TT?u(J?)Ǎ ?6_Z=?z?IGq%?5u7T?P(J?^z?O|P%?F:XT?WK(J?lT? (J?iM!t?η%?ԏT?^(J?ST?(J?T?Y`(J? tests/meshes/vtu/01_raw_binary_int64.vtu000066400000000000000000000254621456244072500205650ustar00rootroot00000000000000 _???ƀ?-Y=??ƀ?-Y=???ƀ?-Y=???ƀ?-Y=?ƀ?-Y=???ƀ?-Y=???e x?)l %?ƀ?-Y=?ƀ?-Y=?ƀ?-Y=?ƀ?-Y=??e x?)l %?ƀ?-Y=?e x?)l %?ƀ?-Y=?e x?)l %??e x?)l %??e x?)l %?ƀ?-Y=? T?(J?e x?)l %?e x?)l %?e x?)l %?e x?)l %? T?(J?ƀ?-Y=?e x?)l %? T?(J?ƀ?-Y=?e x?)l %?? T?(J? T?(J? T?(J?e x?)l %? T?(J? T?(J? T?(J? T?(J?ƀ?-Y=?e x?)l %? T?(J?e x?)l %? T?(J? T?(J?e x?)l %? T?(J? T?(J? T?(J?UUUUUU?UUUUUU???UUUUUU??UUUUUU????UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU??UUUUUU??UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU??UUUUUU??UUUUUU?UUUUUU??UUUUUU???UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU????UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU???UUUUUU??UUUUUU?UUUUUU?UUUUUU?UUUUUU???UUUUUU?UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU??UUUUUU????UUUUUU?UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU????UUUUUU?UUUUUU???UUUUUU?UUUUUU?UUUUUU??UUUUUU?UUUUUU?UUUUUU??UUUUUU??UUUUUU?UUUUUU?UUUUUU??UUUUUU??UUUUUU??@                                         ! "  #$  ! "  % &! !#"'(##'$)! !%"*+ % %* &,!-!(!##'"'.#(#)#'/$)/!-!+!%%*"*.%+ %, %*0 &,0!(-!#(!#1#'.#()#)/#'/2$)/3!+-!%+!%1%*.%+, %,0%*04&,05!(-6!#(1#.1#'.2#()7#)/2)/38!+-6!%+1%.1%*.4%+,9%,04,05:!(16#(17#.12#)27)/28!+16%+19%.14%,49,04:(167#127.12;)278+169%149.14;,49:167<127;278=169<149;49:>17;<27;=19;<49;>7;<=9;<>;<=?;<>?  $(,048<@DHLPTX\`dhlptx|  $(,048<@DHLPTX\`dhlptx|  $(,048<@DHLPTX\`dhlptx| tests/meshes/vtu/02_raw_compressed.vtu000066400000000000000000000052301456244072500204110ustar00rootroot00000000000000 _{xc`@}b;cb;(s;S+T?^L3KO-j'=r;{ضkx=$hqKjQ\|RIu?ĩr?[pxT c3#T*(>AMb4u%]|[u}|uuooAG{WO<}G~PѸB织%N>;ȓKKr9h.tr-cϸT4nKyr=h\*rƝ|7O+&^Ѹ_T4wq?|D=_N={q7߸K>_oDJ߸+ۊ|';_!O=ɧ=tEtɏ}M}.:&wn_0kw1hwTѸ>=]pqV4Ϙ_n}WO܏?g\ : %n\q܋|zȏ'>og|W4wt%/ǒ^??K>ssnmo樂|MMx-p              A B;c;SN;sλK.k[n{{G{g{W^{㭿z>//>rGs 'rgs]rW]s 7rws=O= /oo;}'}7營~9.Î8N88.ˮnxH x~U tests/meshes/wkt/000077500000000000000000000000001456244072500143225ustar00rootroot00000000000000tests/meshes/wkt/simple.wkt000066400000000000000000000001051456244072500163360ustar00rootroot00000000000000TIN (((0 0 0, 0 0 1, 0 1 0, 0 0 0)), ((0 0 0, 0 1 0, 1 1 0, 0 0 0))) tests/meshes/wkt/whitespaced.wkt000066400000000000000000000001471456244072500173530ustar00rootroot00000000000000 TIN ( ((0 0 0, 0 0.00 .1, 0. 0.1 0, 0 0 0)), ( ( 0 0 0 , 0 1 0, 1 1 0, 0 0 0))) tests/performance.py000066400000000000000000000255151456244072500151140ustar00rootroot00000000000000import os import pathlib import tempfile import time import tracemalloc import dufte import matplotlib.pyplot as plt import meshzoo import numpy as np import meshio def generate_triangular_mesh(): p = pathlib.Path("sphere.xdmf") if pathlib.Path.is_file(p): mesh = meshio.read(p) else: points, cells = meshzoo.icosa_sphere(300) mesh = meshio.Mesh(points, {"triangle": cells}) mesh.write(p) return mesh def generate_tetrahedral_mesh(): """Generates a fairly large mesh.""" if pathlib.Path.is_file("cache.xdmf"): mesh = meshio.read("cache.xdmf") else: import pygalmesh s = pygalmesh.Ball([0, 0, 0], 1.0) mesh = pygalmesh.generate_mesh(s, cell_size=2.0e-2, verbose=True) # mesh = pygalmesh.generate_mesh(s, cell_size=1.0e-1, verbose=True) mesh.cells = {"tetra": mesh.cells["tetra"]} mesh.point_data = [] mesh.cell_data = {"tetra": {}} mesh.write("cache.xdmf") return mesh def plot_speed(names, elapsed_write, elapsed_read): plt.style.use(dufte.style) names = np.asarray(names) elapsed_write = np.asarray(elapsed_write) elapsed_read = np.asarray(elapsed_read) fig, ax = plt.subplots(1, 2, figsize=(12, 8)) idx = np.argsort(elapsed_write)[::-1] ax[0].barh(range(len(names)), elapsed_write[idx], align="center") ax[0].set_yticks(range(len(names))) ax[0].set_yticklabels(names[idx]) ax[0].set_xlabel("time (s)") ax[0].set_title("write") ax[0].grid() idx = np.argsort(elapsed_read)[::-1] ax[1].barh(range(len(names)), elapsed_read[idx], align="center") ax[1].set_yticks(range(len(names))) ax[1].set_yticklabels(names[idx]) ax[1].set_xlabel("time (s)") ax[1].set_title("read") ax[1].grid() fig.tight_layout() # plt.show() fig.savefig("performance.svg", transparent=True, bbox_inches="tight") plt.close() def plot_file_sizes(names, file_sizes, mem_size): idx = np.argsort(file_sizes) file_sizes = [file_sizes[i] for i in idx] names = [names[i] for i in idx] plt.figure(figsize=(8, 8)) ax = plt.gca() y_pos = np.arange(len(file_sizes)) ax.barh(y_pos, file_sizes, align="center") # ylim = ax.get_ylim() plt.plot( [mem_size, mem_size], [-2, len(file_sizes) + 2], "C3", linewidth=2.0, zorder=0 ) ax.set_ylim(ylim) # ax.set_yticks(y_pos) ax.set_yticklabels(names) ax.invert_yaxis() # labels read top-to-bottom ax.set_xlabel("file size [MB]") ax.set_title("file sizes") plt.grid() # plt.show() plt.savefig("filesizes.svg", transparent=True, bbox_inches="tight") plt.close() def plot_memory_usage(names, peak_memory_write, peak_memory_read, mem_size): names = np.asarray(names) peak_memory_write = np.asarray(peak_memory_write) peak_memory_read = np.asarray(peak_memory_read) fig, ax = plt.subplots(1, 2, figsize=(12, 8)) idx = np.argsort(peak_memory_write)[::-1] ax[0].barh(range(len(names)), peak_memory_write[idx], align="center") ax[0].set_yticks(range(len(names))) ax[0].set_yticklabels(names[idx]) ax[0].set_xlabel("peak memory [MB]") ax[0].set_title("write") ax[0].grid() # plot memsize of mesh ylim = ax[0].get_ylim() ax[0].plot( [mem_size, mem_size], [-2, len(names) + 2], "C3", linewidth=2.0, zorder=0 ) ax[0].set_ylim(ylim) idx = np.argsort(peak_memory_read)[::-1] ax[1].barh(range(len(names)), peak_memory_read[idx], align="center") ax[1].set_yticks(range(len(names))) ax[1].set_yticklabels(names[idx]) ax[1].set_xlabel("peak memory [MB]") ax[1].set_title("read") ax[1].grid() # plot memsize of mesh ylim = ax[1].get_ylim() ax[1].plot( [mem_size, mem_size], [-2, len(names) + 2], "C3", linewidth=2.0, zorder=0 ) ax[1].set_ylim(ylim) fig.tight_layout() # plt.show() fig.savefig("memory.svg", transparent=True, bbox_inches="tight") plt.close() def read_write(plot=False): # mesh = generate_tetrahedral_mesh() mesh = generate_triangular_mesh() print(mesh) mem_size = mesh.points.nbytes + mesh.cells[0].data.nbytes mem_size /= 1024.0**2 print(f"mem_size: {mem_size:.2f} MB") formats = { "Abaqus": (meshio.abaqus.write, meshio.abaqus.read, ["out.inp"]), "Ansys (ASCII)": ( lambda f, m: meshio.ansys.write(f, m, binary=False), meshio.ansys.read, ["out.ans"], ), # "Ansys (binary)": ( # lambda f, m: meshio.ansys.write(f, m, binary=True), # meshio.ansys.read, # ["out.ans"], # ), "AVS-UCD": (meshio.avsucd.write, meshio.avsucd.read, ["out.ucd"]), # "CGNS": (meshio.cgns.write, meshio.cgns.read, ["out.cgns"]), "Dolfin-XML": (meshio.dolfin.write, meshio.dolfin.read, ["out.xml"]), "Exodus": (meshio.exodus.write, meshio.exodus.read, ["out.e"]), # "FLAC3D": (meshio.flac3d.write, meshio.flac3d.read, ["out.f3grid"]), "Gmsh 4.1 (ASCII)": ( lambda f, m: meshio.gmsh.write(f, m, binary=False), meshio.gmsh.read, ["out.msh"], ), "Gmsh 4.1 (binary)": ( lambda f, m: meshio.gmsh.write(f, m, binary=True), meshio.gmsh.read, ["out.msh"], ), "MDPA": (meshio.mdpa.write, meshio.mdpa.read, ["out.mdpa"]), "MED": (meshio.med.write, meshio.med.read, ["out.med"]), "Medit": (meshio.medit.write, meshio.medit.read, ["out.mesh"]), "MOAB": (meshio.h5m.write, meshio.h5m.read, ["out.h5m"]), "Nastran": (meshio.nastran.write, meshio.nastran.read, ["out.bdf"]), "Netgen": (meshio.netgen.write, meshio.netgen.read, ["out.vol"]), "OFF": (meshio.off.write, meshio.off.read, ["out.off"]), "Permas": (meshio.permas.write, meshio.permas.read, ["out.dato"]), "PLY (binary)": ( lambda f, m: meshio.ply.write(f, m, binary=True), meshio.ply.read, ["out.ply"], ), "PLY (ASCII)": ( lambda f, m: meshio.ply.write(f, m, binary=False), meshio.ply.read, ["out.ply"], ), "STL (binary)": ( lambda f, m: meshio.stl.write(f, m, binary=True), meshio.stl.read, ["out.stl"], ), "STL (ASCII)": ( lambda f, m: meshio.stl.write(f, m, binary=False), meshio.stl.read, ["out.stl"], ), # "TetGen": (meshio.tetgen.write, meshio.tetgen.read, ["out.node", "out.ele"],), "VTK (binary)": ( lambda f, m: meshio.vtk.write(f, m, binary=True), meshio.vtk.read, ["out.vtk"], ), "VTK (ASCII)": ( lambda f, m: meshio.vtk.write(f, m, binary=False), meshio.vtk.read, ["out.vtk"], ), "VTU (binary, uncompressed)": ( lambda f, m: meshio.vtu.write(f, m, binary=True, compression=None), meshio.vtu.read, ["out.vtu"], ), "VTU (binary, zlib)": ( lambda f, m: meshio.vtu.write(f, m, binary=True, compression="zlib"), meshio.vtu.read, ["out.vtu"], ), "VTU (binary, LZMA)": ( lambda f, m: meshio.vtu.write(f, m, binary=True, compression="lzma"), meshio.vtu.read, ["out.vtu"], ), "VTU (ASCII)": ( lambda f, m: meshio.vtu.write(f, m, binary=False), meshio.vtu.read, ["out.vtu"], ), "Wavefront .obj": (meshio.obj.write, meshio.obj.read, ["out.obj"]), # "wkt": ".wkt", "XDMF (binary)": ( lambda f, m: meshio.xdmf.write(f, m, data_format="Binary"), meshio.xdmf.read, ["out.xdmf", "out0.bin", "out1.bin"], ), "XDMF (HDF, GZIP)": ( lambda f, m: meshio.xdmf.write(f, m, data_format="HDF", compression="gzip"), meshio.xdmf.read, ["out.xdmf", "out.h5"], ), "XDMF (HDF, uncompressed)": ( lambda f, m: meshio.xdmf.write(f, m, data_format="HDF", compression=None), meshio.xdmf.read, ["out.xdmf", "out.h5"], ), "XDMF (XML)": ( lambda f, m: meshio.xdmf.write(f, m, data_format="XML"), meshio.xdmf.read, ["out.xdmf"], ), } # formats = { # # "VTK (ASCII)": formats["VTK (ASCII)"], # # "VTK (binary)": formats["VTK (binary)"], # # "VTU (ASCII)": formats["VTU (ASCII)"], # # "VTU (binary)": formats["VTU (binary)"], # # "Gmsh 4.1 (binary)": formats["Gmsh 4.1 (binary)"], # # "FLAC3D": formats["FLAC3D"], # "MDPA": formats["MDPA"], # } # max_key_length = max(len(key) for key in formats) elapsed_write = [] elapsed_read = [] file_sizes = [] peak_memory_write = [] peak_memory_read = [] print() print( "format " + "write (s) " + "read(s) " + "file size " + "write mem " + "read mem " ) print() with tempfile.TemporaryDirectory() as directory: directory = pathlib.Path(directory) for name, (writer, reader, filenames) in formats.items(): filename = directory / filenames[0] tracemalloc.start() t = time.time() writer(filename, mesh) # snapshot = tracemalloc.take_snapshot() elapsed_write.append(time.time() - t) peak_memory_write.append(tracemalloc.get_traced_memory()[1]) tracemalloc.stop() file_sizes.append(sum(os.stat(directory / f).st_size for f in filenames)) tracemalloc.start() t = time.time() reader(filename) elapsed_read.append(time.time() - t) peak_memory_read.append(tracemalloc.get_traced_memory()[1]) tracemalloc.stop() print( "{:<26} {:e} {:e} {:e} {:e} {:e}".format( name, elapsed_write[-1], elapsed_read[-1], file_sizes[-1] / 1024.0**2, peak_memory_write[-1] / 1024.0**2, peak_memory_read[-1] / 1024.0**2, ) ) names = list(formats.keys()) # convert to MB file_sizes = np.array(file_sizes) file_sizes = file_sizes / 1024.0**2 peak_memory_write = np.array(peak_memory_write) peak_memory_write = peak_memory_write / 1024.0**2 peak_memory_read = np.array(peak_memory_read) peak_memory_read = peak_memory_read / 1024.0**2 if plot: plot_speed(names, elapsed_write, elapsed_read) plot_file_sizes(names, file_sizes, mem_size) plot_memory_usage(names, peak_memory_write, peak_memory_read, mem_size) if __name__ == "__main__": read_write(plot=True) tests/test_abaqus.py000066400000000000000000000043071456244072500151220ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.tri_mesh, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, ], ) def test(mesh, tmp_path): helpers.write_read(tmp_path, meshio.abaqus.write, meshio.abaqus.read, mesh, 1.0e-15) @pytest.mark.parametrize( "filename, ref_sum, ref_num_cells, ref_num_cell_sets", [ ("UUea.inp", 4950.0, 50, 10), ("nle1xf3c.inp", 32.215275528, 12, 3), ("element_elset.inp", 6.0, 2, 3), ("wInclude_main.inp", 1.5, 2, 0), ], ) def test_reference_file(filename, ref_sum, ref_num_cells, ref_num_cell_sets): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "abaqus" / filename mesh = meshio.read(filename) assert np.isclose(np.sum(mesh.points), ref_sum) assert sum(len(cells.data) for cells in mesh.cells) == ref_num_cells assert len(mesh.cell_sets) == ref_num_cell_sets def test_elset(tmp_path): points = np.array( [[1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [2.0, 0.5, 0.0], [0.0, 0.5, 0.0]] ) cells = [ ("triangle", np.array([[0, 1, 2]])), ("triangle", np.array([[0, 1, 3]])), ] cell_sets = { "right": [np.array([0]), np.array([])], "left": [np.array([]), np.array([1])], } mesh_ref = meshio.Mesh(points, cells, cell_sets=cell_sets) filepath = tmp_path / "test.inp" meshio.abaqus.write(filepath, mesh_ref) mesh = meshio.abaqus.read(filepath) assert np.allclose(mesh_ref.points, mesh.points) assert len(mesh_ref.cells) == len(mesh.cells) for ic, cell in enumerate(mesh_ref.cells): assert cell.type == mesh.cells[ic].type assert np.allclose(cell.data, mesh.cells[ic].data) assert sorted(mesh_ref.cell_sets.keys()) == sorted(mesh.cell_sets.keys()) for k, v in mesh_ref.cell_sets.items(): for ic in range(len(mesh_ref.cells)): assert np.allclose(v[ic], mesh.cell_sets[k][ic]) tests/test_ansys.py000066400000000000000000000011511456244072500147750ustar00rootroot00000000000000import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.tri_mesh, helpers.tri_mesh_2d, helpers.quad_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.hex_mesh, helpers.pyramid_mesh, helpers.wedge_mesh, ], ) @pytest.mark.parametrize("binary", [False, True]) def test(mesh, binary, tmp_path): def writer(*args, **kwargs): return meshio.ansys.write(*args, binary=binary, **kwargs) helpers.write_read(tmp_path, writer, meshio.ansys.read, mesh, 1.0e-15) tests/test_avsucd.py000066400000000000000000000011541456244072500151300ustar00rootroot00000000000000import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.tri_mesh, helpers.quad_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.hex_mesh, helpers.add_cell_data( helpers.tri_mesh, [("avsucd:material", (), int), ("a", (), float), ("b", (3,), float)], ), helpers.add_point_data(helpers.add_point_data(helpers.tri_mesh, 1), 3), ], ) def test(mesh, tmp_path): helpers.write_read(tmp_path, meshio.avsucd.write, meshio.avsucd.read, mesh, 1.0e-13) tests/test_cgns.py000066400000000000000000000004211456244072500145710ustar00rootroot00000000000000import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ # helpers.empty_mesh, helpers.tet_mesh ], ) def test(mesh, tmp_path): helpers.write_read(tmp_path, meshio.cgns.write, meshio.cgns.read, mesh, 1.0e-15) tests/test_cli.py000066400000000000000000000041361456244072500144150ustar00rootroot00000000000000import numpy as np import meshio from . import helpers def is_same_mesh(mesh0, mesh1, atol): if not np.allclose(mesh0.points, mesh1.points, atol=atol, rtol=0.0): return False for cells0, cells1 in zip(mesh0.cells, mesh1.cells): if cells0.type != cells1.type or not np.allclose(cells0.data, cells1.data): return False return True def test_info(tmp_path): infile = tmp_path / "out.msh" meshio.write(infile, helpers.tri_mesh, file_format="gmsh") meshio._cli.main(["info", str(infile), "--input-format", "gmsh"]) def test_convert(tmp_path): input_mesh = helpers.tri_mesh infile = tmp_path / "in.msh" meshio.write(infile, helpers.tri_mesh, file_format="gmsh") outfile = tmp_path / "out.msh" meshio._cli.main( [ "convert", str(infile), str(outfile), "--input-format", "gmsh", "--output-format", "vtk", "--sets-to-int-data", ] ) mesh = meshio.read(outfile, file_format="vtk") atol = 1.0e-15 assert np.allclose(input_mesh.points, mesh.points, atol=atol, rtol=0.0) for cells0, cells1 in zip(input_mesh.cells, mesh.cells): assert cells0.type == cells1.type assert np.allclose(cells0.data, cells1.data) def test_compress(tmp_path): input_mesh = helpers.tri_mesh infile = tmp_path / "in.vtu" meshio.write(infile, input_mesh) meshio._cli.main(["decompress", str(infile)]) mesh = meshio.read(infile) assert is_same_mesh(input_mesh, mesh, atol=1.0e-15) meshio._cli.main(["compress", str(infile)]) mesh = meshio.read(infile) assert is_same_mesh(input_mesh, mesh, atol=1.0e-15) def test_ascii_binary(tmp_path): input_mesh = helpers.tri_mesh infile = tmp_path / "in.vtu" meshio.write(infile, input_mesh) meshio._cli.main(["ascii", str(infile)]) mesh = meshio.read(infile) assert is_same_mesh(input_mesh, mesh, atol=1.0e-12) meshio._cli.main(["binary", str(infile)]) mesh = meshio.read(infile) assert is_same_mesh(input_mesh, mesh, atol=1.0e-12) tests/test_dolfin.py000066400000000000000000000012031456244072500151110ustar00rootroot00000000000000import numpy as np import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ # helpers.empty_mesh, helpers.tri_mesh, helpers.tri_mesh_2d, helpers.tet_mesh, helpers.add_cell_data( helpers.tri_mesh, [("a", (), float), ("b", (), np.int64)] ), ], ) def test_dolfin(mesh, tmp_path): helpers.write_read(tmp_path, meshio.dolfin.write, meshio.dolfin.read, mesh, 1.0e-15) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.xml") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.xml") tests/test_exodus.py000066400000000000000000000016611456244072500151550ustar00rootroot00000000000000import pytest import meshio from . import helpers netCDF4 = pytest.importorskip("netCDF4") test_set = [ helpers.empty_mesh, helpers.tri_mesh, helpers.tri_mesh_2d, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, helpers.add_point_data(helpers.tri_mesh, 1), helpers.add_point_data(helpers.tri_mesh, 2), helpers.add_point_data(helpers.tri_mesh, 3), helpers.add_point_sets(helpers.tri_mesh), helpers.add_point_sets(helpers.tet_mesh), ] @pytest.mark.parametrize("mesh", test_set) def test_io(mesh, tmp_path): helpers.write_read(tmp_path, meshio.exodus.write, meshio.exodus.read, mesh, 1.0e-15) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.e") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.e") tests/test_flac3d.py000066400000000000000000000030041456244072500147730ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.tet_mesh, helpers.hex_mesh, helpers.tet_mesh, helpers.add_cell_sets(helpers.tet_mesh), ], ) @pytest.mark.parametrize("binary", [False, True]) def test(mesh, binary, tmp_path): # mesh.write("out.f3grid") helpers.write_read( tmp_path, lambda f, m: meshio.flac3d.write(f, m, binary=binary), meshio.flac3d.read, mesh, 1.0e-15, ) @pytest.mark.parametrize( "filename", ["flac3d_mesh_ex.f3grid", "flac3d_mesh_ex_bin.f3grid"], ) def test_reference_file(filename): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "flac3d" / filename mesh = meshio.read(filename) # points assert np.isclose(mesh.points.sum(), 307.0) # cells ref_num_cells = [ ("quad", 15), ("triangle", 3), ("hexahedron", 45), ("pyramid", 9), ("hexahedron", 18), ("wedge", 9), ("hexahedron", 6), ("wedge", 3), ("hexahedron", 6), ("wedge", 3), ("pyramid", 6), ("tetra", 3), ] assert [ (cell_block.type, len(cell_block)) for cell_block in mesh.cells ] == ref_num_cells # Cell sets for arr in mesh.cell_sets.values(): assert len(arr) == 12 assert [len(arr) for arr in mesh.cell_sets.values()] == [12, 12, 12, 12, 12] tests/test_gmsh.py000066400000000000000000000143421456244072500146040ustar00rootroot00000000000000import copy import pathlib from functools import partial import numpy as np import pytest import meshio from . import helpers def gmsh_periodic(): mesh = copy.deepcopy(helpers.quad_mesh) trns = [0] * 16 # just for io testing mesh.gmsh_periodic = [ [0, (3, 1), None, [[2, 0]]], [0, (4, 6), None, [[3, 5]]], [1, (2, 1), trns, [[5, 0], [4, 1], [4, 2]]], ] return mesh @pytest.mark.parametrize( "mesh", [ # helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, # helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, helpers.add_point_data(helpers.tri_mesh, 1), helpers.add_point_data(helpers.tri_mesh, 3), helpers.add_point_data(helpers.tri_mesh, 9), helpers.add_cell_data(helpers.tri_mesh, [("a", (), np.float64)]), helpers.add_cell_data(helpers.tri_mesh, [("a", (3,), np.float64)]), helpers.add_cell_data(helpers.tri_mesh, [("a", (9,), np.float64)]), helpers.add_field_data(helpers.tri_mesh, [1, 2], int), helpers.add_field_data(helpers.tet_mesh, [1, 3], int), helpers.add_field_data(helpers.hex_mesh, [1, 3], int), gmsh_periodic(), ], ) @pytest.mark.parametrize("binary", [False, True]) def test_gmsh22(mesh, binary, tmp_path): writer = partial(meshio.gmsh.write, fmt_version="2.2", binary=binary) helpers.write_read(tmp_path, writer, meshio.gmsh.read, mesh, 1.0e-15) @pytest.mark.parametrize( "mesh", [ helpers.tri_mesh, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, # helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, helpers.add_point_data(helpers.tri_mesh, 1), helpers.add_point_data(helpers.tri_mesh, 3), helpers.add_point_data(helpers.tri_mesh, 9), helpers.add_cell_data(helpers.tri_mesh, [("a", (), np.float64)]), helpers.add_cell_data(helpers.tri_mesh, [("a", (3,), np.float64)]), helpers.add_cell_data(helpers.tri_mesh, [("a", (9,), np.float64)]), helpers.add_field_data(helpers.tri_mesh, [1, 2], int), helpers.add_field_data(helpers.tet_mesh, [1, 3], int), helpers.add_field_data(helpers.hex_mesh, [1, 3], int), ], ) @pytest.mark.parametrize("binary", [False, True]) def test_gmsh40(mesh, binary, tmp_path): writer = partial(meshio.gmsh.write, fmt_version="4.0", binary=binary) helpers.write_read(tmp_path, writer, meshio.gmsh.read, mesh, 1.0e-15) @pytest.mark.parametrize( "mesh", [ helpers.tri_mesh, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, # helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, helpers.add_point_data(helpers.tri_mesh, 1), helpers.add_point_data(helpers.tri_mesh, 3), helpers.add_point_data(helpers.tri_mesh, 9), helpers.add_cell_data(helpers.tri_mesh, [("a", (), np.float64)]), helpers.add_cell_data(helpers.tri_mesh, [("a", (3,), np.float64)]), helpers.add_cell_data(helpers.tri_mesh, [("a", (9,), np.float64)]), helpers.add_field_data(helpers.tri_mesh, [1, 2], int), helpers.add_field_data(helpers.tet_mesh, [1, 3], int), helpers.add_field_data(helpers.hex_mesh, [1, 3], int), gmsh_periodic(), ], ) @pytest.mark.parametrize("binary", [False, True]) def test_gmsh41(mesh, binary, tmp_path): writer = partial(meshio.gmsh.write, fmt_version="4.1", binary=binary) helpers.write_read(tmp_path, writer, meshio.gmsh.read, mesh, 1.0e-15) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.msh") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.msh") @pytest.mark.parametrize( "filename, ref_sum, ref_num_cells", [("insulated-2.2.msh", 2.001762136876221, [21, 111])], ) @pytest.mark.parametrize("binary", [False, True]) def test_reference_file(filename, ref_sum, ref_num_cells, binary, tmp_path): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "msh" / filename mesh = meshio.read(filename) tol = 1.0e-2 s = mesh.points.sum() assert abs(s - ref_sum) < tol * ref_sum assert [c.type for c in mesh.cells] == ["line", "triangle"] assert [len(c.data) for c in mesh.cells] == ref_num_cells assert list(map(len, mesh.cell_data["gmsh:geometrical"])) == ref_num_cells assert list(map(len, mesh.cell_data["gmsh:physical"])) == ref_num_cells writer = partial(meshio.gmsh.write, fmt_version="2.2", binary=binary) helpers.write_read(tmp_path, writer, meshio.gmsh.read, mesh, 1.0e-15) @pytest.mark.parametrize( "filename, ref_sum, ref_num_cells, ref_num_cells_in_cell_sets", [ ( "insulated-4.1.msh", 2.001762136876221, {"line": 21, "triangle": 111}, {"line": 27, "triangle": 120}, ) ], # Note that testing on number of cells in # cell_sets_dict will count both cells associated with physical tags, and # bounding entities. ) @pytest.mark.parametrize("binary", [False, True]) def test_reference_file_with_entities( filename, ref_sum, ref_num_cells, ref_num_cells_in_cell_sets, binary, tmp_path ): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "msh" / filename mesh = meshio.read(filename) tol = 1.0e-2 s = mesh.points.sum() assert abs(s - ref_sum) < tol * ref_sum assert {k: len(v) for k, v in mesh.cells_dict.items()} == ref_num_cells assert { k: len(v) for k, v in mesh.cell_data_dict["gmsh:physical"].items() } == ref_num_cells writer = partial(meshio.gmsh.write, fmt_version="4.1", binary=binary) num_cells = {k: 0 for k in ref_num_cells_in_cell_sets} for vv in mesh.cell_sets_dict.values(): for k, v in vv.items(): num_cells[k] += len(v) assert num_cells == ref_num_cells_in_cell_sets helpers.write_read(tmp_path, writer, meshio.gmsh.read, mesh, 1.0e-15) tests/test_helpers.py000066400000000000000000000016441456244072500153110ustar00rootroot00000000000000from pathlib import Path import pytest import meshio OBJ_PATH = Path(__file__).resolve().parent / "meshes" / "ply" / "bun_zipper_res4.ply" def test_read_str(): meshio.read(str(OBJ_PATH)) def test_read_pathlike(): meshio.read(OBJ_PATH) @pytest.mark.skip def test_read_buffer(): with open(str(OBJ_PATH)) as f: meshio.read(f, "ply") @pytest.fixture def mesh(): return meshio.read(OBJ_PATH) def test_write_str(mesh, tmpdir): tmp_path = str(tmpdir.join("tmp.ply")) meshio.write(tmp_path, mesh) assert Path(tmp_path).is_file() def test_write_pathlike(mesh, tmpdir): tmp_path = Path(tmpdir.join("tmp.ply")) meshio.write(tmp_path, mesh) assert Path(tmp_path).is_file() @pytest.mark.skip def test_write_buffer(mesh, tmpdir): tmp_path = str(tmpdir.join("tmp.ply")) with open(tmp_path, "w") as f: meshio.write(f, mesh, "ply") assert Path(tmp_path).is_file() tests/test_hmf.py000066400000000000000000000021551456244072500144170ustar00rootroot00000000000000import numpy as np import pytest import meshio from . import helpers test_set_full = [ helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh, helpers.line_tri_mesh, helpers.tri_mesh_2d, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, helpers.add_point_data(helpers.tri_mesh, 1), helpers.add_cell_data(helpers.tri_mesh, [("a", (), np.float64)]), ] @pytest.mark.parametrize("mesh", test_set_full) @pytest.mark.parametrize("compression", [None, "gzip"]) def test_xdmf3(mesh, compression, tmp_path): def write(*args, **kwargs): return meshio.xdmf.write(*args, compression=compression, **kwargs) helpers.write_read(tmp_path, write, meshio.xdmf.read, mesh, 1.0e-14) @pytest.mark.skip def test_generic_io(tmp_path): with pytest.warns(UserWarning): helpers.generic_io(tmp_path / "test.hmf") with pytest.warns(UserWarning): # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.hmf") tests/test_mdpa.py000066400000000000000000000024551456244072500145710ustar00rootroot00000000000000import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, # helpers.add_point_data(helpers.tri_mesh, 1), # NOTE: Data not supported yet # helpers.add_point_data(helpers.tri_mesh, 3), # helpers.add_point_data(helpers.tri_mesh, 9), # helpers.add_cell_data(helpers.tri_mesh, [("a", (), np.float64)]), # helpers.add_cell_data(helpers.tri_mesh, [("a", (3,), np.float64)]), # helpers.add_cell_data(helpers.tri_mesh, [("a", (9,), np.float64)]), # helpers.add_field_data(helpers.tri_mesh, [1, 2], int), # helpers.add_field_data(helpers.tet_mesh, [1, 3], int), # helpers.add_field_data(helpers.hex_mesh, [1, 3], int), ], ) def test_io(mesh, tmp_path): helpers.write_read(tmp_path, meshio.mdpa.write, meshio.mdpa.read, mesh, 1.0e-15) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.mesh") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.mesh") tests/test_med.py000066400000000000000000000101171456244072500144070ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers h5py = pytest.importorskip("h5py") @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh_2d, helpers.tri_mesh, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.quad_tri_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, helpers.add_point_data(helpers.tri_mesh, 1), helpers.add_point_data(helpers.tri_mesh, 2), helpers.add_point_data(helpers.tri_mesh, 3), helpers.add_point_data(helpers.hex_mesh, 3), helpers.add_cell_data(helpers.tri_mesh, [("a", (), np.float64)]), helpers.add_cell_data(helpers.tri_mesh, [("a", (2,), np.float64)]), helpers.add_cell_data(helpers.tri_mesh, [("a", (3,), np.float64)]), ], ) def test_io(mesh, tmp_path): helpers.write_read(tmp_path, meshio.med.write, meshio.med.read, mesh, 1.0e-15) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.med") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.med") def test_reference_file_with_mixed_cells(tmp_path): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "med" / "cylinder.med" mesh = meshio.read(filename) # Points assert np.isclose(mesh.points.sum(), 16.53169892762988) # CellBlock ref_num_cells = {"pyramid": 18, "quad": 18, "line": 17, "tetra": 63, "triangle": 4} assert { cell_block.type: len(cell_block) for cell_block in mesh.cells } == ref_num_cells # Point tags assert mesh.point_data["point_tags"].sum() == 52 ref_point_tags_info = {2: ["Side"], 3: ["Side", "Top"], 4: ["Top"]} assert mesh.point_tags == ref_point_tags_info # Cell tags ref_sum_cell_tags = { "pyramid": -116, "quad": -75, "line": -48, "tetra": -24, "triangle": -30, } assert { c.type: sum(d) for c, d in zip(mesh.cells, mesh.cell_data["cell_tags"]) } == ref_sum_cell_tags ref_cell_tags_info = { -6: ["Top circle"], -7: ["Top", "Top and down"], -8: ["Top and down"], -9: ["A", "B"], -10: ["B"], -11: ["B", "C"], -12: ["C"], } assert mesh.cell_tags == ref_cell_tags_info helpers.write_read(tmp_path, meshio.med.write, meshio.med.read, mesh, 1.0e-15) def test_reference_file_with_point_cell_data(tmp_path): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "med" / "box.med" mesh = meshio.read(filename) # Points assert np.isclose(mesh.points.sum(), 12) # CellBlock assert {cell_block.type: len(cell_block) for cell_block in mesh.cells} == { "hexahedron": 1 } # Point data data_u = mesh.point_data["resu____DEPL"] assert data_u.shape == (8, 3) assert np.isclose(data_u.sum(), 12) # Cell data # ELNO (1 data point for every node of each element) data_eps = mesh.cell_data["resu____EPSI_ELNO"][0] assert data_eps.shape == (1, 8, 6) # (n_cells, n_nodes_per_element, n_components) data_eps_mean = np.mean(data_eps, axis=1)[0] eps_ref = np.array([1, 0, 0, 0.5, 0.5, 0]) assert np.allclose(data_eps_mean, eps_ref) data_sig = mesh.cell_data["resu____SIEF_ELNO"][0] assert data_sig.shape == (1, 8, 6) # (n_cells, n_nodes_per_element, n_components) data_sig_mean = np.mean(data_sig, axis=1)[0] sig_ref = np.array( [7328.44611253, 2645.87030114, 2034.06063679, 1202.6, 569.752, 0] ) assert np.allclose(data_sig_mean, sig_ref) data_psi = mesh.cell_data["resu____ENEL_ELNO"][0] assert data_psi.shape == (1, 8, 1) # (n_cells, n_nodes_per_element, n_components) # ELEM (1 data point for each element) data_psi_elem = mesh.cell_data["resu____ENEL_ELEM"][0] assert np.isclose(np.mean(data_psi, axis=1)[0, 0], data_psi_elem[0]) helpers.write_read(tmp_path, meshio.med.write, meshio.med.read, mesh, 1.0e-15) tests/test_medit.py000066400000000000000000000073121456244072500147470ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh, helpers.tri_mesh_2d, helpers.quad_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.hex_mesh, helpers.add_cell_data(helpers.tri_mesh, [("medit:ref", (), int)]), ], ) def test_io(mesh, tmp_path): helpers.write_read(tmp_path, meshio.medit.write, meshio.medit.read, mesh, 1.0e-15) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.mesh") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.mesh") # same for binary files helpers.generic_io(tmp_path / "test.meshb") helpers.generic_io(tmp_path / "test.0.meshb") # same tests with ugrid format files converted with UGC from # https://www.simcenter.msstate.edu/ @pytest.mark.parametrize( "filename, ref_num_points, ref_num_triangle, ref_num_quad, ref_num_wedge, ref_num_tet, ref_num_hex, ref_tag_counts", [ ( "sphere_mixed.1.meshb", 3270, 864, 0, 3024, 9072, 0, {1: 432, 2: 216, 3: 216}, ), ("hch_strct.4.meshb", 306, 12, 178, 96, 0, 144, {1: 15, 2: 15, 3: 160}), ("hch_strct.4.be.meshb", 306, 12, 178, 96, 0, 144, {1: 15, 2: 15, 3: 160}), ("cube86.mesh", 39, 72, 0, 0, 86, 0, {1: 14, 2: 14, 3: 14, 4: 8, 5: 14, 6: 8}), ], ) def test_reference_file( filename, ref_num_points, ref_num_triangle, ref_num_quad, ref_num_wedge, ref_num_tet, ref_num_hex, ref_tag_counts, ): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "medit" / filename mesh = meshio.read(filename) assert mesh.points.shape[0] == ref_num_points assert mesh.points.shape[1] == 3 medit_meshio_id = { "triangle": None, "quad": None, "tetra": None, "pyramid": None, "wedge": None, "hexahedron": None, } for i, cell_block in enumerate(mesh.cells): if cell_block.type in medit_meshio_id: medit_meshio_id[cell_block.type] = i # validate element counts if ref_num_triangle > 0: c = mesh.cells[medit_meshio_id["triangle"]] assert c.data.shape == (ref_num_triangle, 3) else: assert medit_meshio_id["triangle"] is None if ref_num_quad > 0: c = mesh.cells[medit_meshio_id["quad"]] assert c.data.shape == (ref_num_quad, 4) else: assert medit_meshio_id["quad"] is None if ref_num_tet > 0: c = mesh.cells[medit_meshio_id["tetra"]] assert c.data.shape == (ref_num_tet, 4) else: assert medit_meshio_id["tetra"] is None if ref_num_wedge > 0: c = mesh.cells[medit_meshio_id["wedge"]] assert c.data.shape == (ref_num_wedge, 6) else: assert medit_meshio_id["wedge"] is None if ref_num_hex > 0: c = mesh.cells[medit_meshio_id["hexahedron"]] assert c.data.shape == (ref_num_hex, 8) else: assert medit_meshio_id["hexahedron"] is None # validate boundary tags # gather tags all_tags = [] for k, c in enumerate(mesh.cells): if c.type not in ["triangle", "quad"]: continue all_tags.append(mesh.cell_data["medit:ref"][k]) all_tags = np.concatenate(all_tags) # validate against known values unique, counts = np.unique(all_tags, return_counts=True) tags = dict(zip(unique, counts)) assert tags.keys() == ref_tag_counts.keys() for key in tags.keys(): assert tags[key] == ref_tag_counts[key] tests/test_mesh.py000066400000000000000000000057571456244072500146140ustar00rootroot00000000000000import copy import numpy as np import pytest from numpy.testing import assert_equal import meshio from . import helpers def test_cells_dict(): mesh = copy.deepcopy(helpers.tri_mesh) assert len(mesh.cells_dict) == 1 assert np.array_equal(mesh.cells_dict["triangle"], [[0, 1, 2], [0, 2, 3]]) # two cells groups mesh = meshio.Mesh( [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]], [("triangle", [[0, 1, 2]]), ("triangle", [[0, 2, 3]])], cell_data={"a": [[0.5], [1.3]]}, ) assert len(mesh.cells_dict) == 1 assert_equal(mesh.cells_dict, {"triangle": [[0, 1, 2], [0, 2, 3]]}) assert_equal(mesh.cell_data_dict, {"a": {"triangle": [0.5, 1.3]}}) def test_sets_to_int_data(): mesh = helpers.tri_mesh_5 mesh = helpers.add_point_sets(mesh) mesh = helpers.add_cell_sets(mesh) mesh.point_sets_to_data() mesh.cell_sets_to_data() assert mesh.cell_sets == {} assert_equal(mesh.cell_data, {"grain0-grain1": [[0, 0, 1, 1, 1]]}) assert mesh.point_sets == {} assert_equal(mesh.point_data, {"fixed-loose": [0, 0, 0, 1, 1, 1, 1]}) # now back to set data mesh.cell_data_to_sets("grain0-grain1") mesh.point_data_to_sets("fixed-loose") assert mesh.cell_data == {} assert_equal(mesh.cell_sets, {"grain0": [[0, 1]], "grain1": [[2, 3, 4]]}) assert mesh.point_data == {} assert_equal(mesh.point_sets, {"fixed": [0, 1, 2], "loose": [3, 4, 5, 6]}) @pytest.mark.skip def test_sets_to_int_data_warning(): mesh = meshio.Mesh( [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]], {"triangle": [[0, 1, 2], [1, 2, 3]]}, cell_sets={"tag": [[0]]}, ) with pytest.warns(UserWarning): mesh.cell_sets_to_data() assert np.all(mesh.cell_data["tag"] == np.array([[0, -1]])) mesh = meshio.Mesh( [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]], {"triangle": [[0, 1, 2], [1, 2, 3]]}, point_sets={"tag": [[0, 1, 3]]}, ) with pytest.warns(UserWarning): mesh.point_sets_to_data() assert np.all(mesh.point_data["tag"] == np.array([[0, 0, -1, 0]])) def test_int_data_to_sets(): mesh = helpers.tri_mesh mesh.cell_data = {"grain0-grain1": [np.array([0, 1])]} mesh.cell_data_to_sets("grain0-grain1") assert_equal(mesh.cell_sets, {"grain0": [[0]], "grain1": [[1]]}) def test_gh_1165(): mesh = meshio.Mesh( [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]], { "triangle": [[0, 1, 2], [1, 2, 3]], "line": [[0, 1], [0, 2], [1, 3], [2, 3]], }, cell_sets={ "test": [[], [1]], "sets": [[0, 1], [0, 2, 3]], }, ) mesh.cell_sets_to_data() mesh.cell_data_to_sets("test-sets") assert_equal(mesh.cell_sets, {"test": [[], [1]], "sets": [[0, 1], [0, 2, 3]]}) def test_copy(): mesh = helpers.tri_mesh mesh2 = mesh.copy() assert np.all(mesh.points == mesh2.points) assert not np.may_share_memory(mesh.points, mesh2.points) tests/test_moab.py000066400000000000000000000010631456244072500145600ustar00rootroot00000000000000import pytest import meshio from . import helpers h5py = pytest.importorskip("h5py") @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh, helpers.tri_mesh_2d, helpers.tet_mesh, ], ) def test_io(mesh, tmp_path): helpers.write_read(tmp_path, meshio.h5m.write, meshio.h5m.read, mesh, 1.0e-15) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.h5m") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.h5m") tests/test_nastran.py000066400000000000000000000027741456244072500153220ustar00rootroot00000000000000import io import pathlib import numpy as np import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.tri_mesh, helpers.tri_mesh_2d, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, ], ) def test(mesh, tmp_path): helpers.write_read( tmp_path, meshio.nastran.write, meshio.nastran.read, mesh, 1.0e-13 ) @pytest.mark.parametrize("filename", ["cylinder.fem", "cylinder_cells_first.fem"]) def test_reference_file(filename): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "nastran" / filename mesh = meshio.read(filename) # points assert np.isclose(mesh.points.sum(), 16.5316866) # cells ref_num_cells = { "line": 241, "triangle": 171, "quad": 721, "pyramid": 1180, "tetra": 5309, } assert { cell_block.type: cell_block.data.sum() for cell_block in mesh.cells } == ref_num_cells def test_long_format(): filename = io.StringIO( "BEGIN BULK\n" "GRID* 43 1.50000000000000 0.0\n" "* 0.\n" "ENDDATA\n" ) mesh = meshio.read(filename, "nastran") # points assert len(mesh.points) == 1 assert np.isclose(mesh.points.sum(), 1.5) tests/test_netgen.py000066400000000000000000000057611456244072500151330ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers test_set = [ helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh_2d, helpers.tri_mesh, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, helpers.pyramid_mesh, helpers.wedge_mesh, helpers.add_cell_data(helpers.tri_mesh, [("netgen:index", (), int)]), ] this_dir = pathlib.Path(__file__).resolve().parent netgen_mesh_directory = this_dir / "meshes" / "netgen" PERIODIC_1D = "periodic_1d.vol" PERIODIC_2D = "periodic_2d.vol" PERIODIC_3D = "periodic_3d.vol" netgen_meshes = [PERIODIC_1D, PERIODIC_2D, PERIODIC_3D] @pytest.mark.parametrize("mesh", test_set) @pytest.mark.parametrize("suffix", [".vol", ".vol.gz"]) def test(mesh, suffix, tmp_path): helpers.write_read( tmp_path, meshio.netgen.write, meshio.netgen.read, mesh, 1.0e-13, extension=suffix, ) expected_identifications = { PERIODIC_1D: np.array([[1, 51, 1]]), PERIODIC_2D: np.array( [[2, 1, 4], [3, 4, 4], [9, 17, 4], [10, 18, 4], [11, 19, 4], [12, 20, 4]] ), PERIODIC_3D: np.array( [ [1, 3, 1], [2, 5, 1], [4, 7, 1], [6, 8, 1], [9, 11, 1], [10, 12, 1], [15, 13, 1], [16, 14, 1], [21, 19, 1], [22, 20, 1], [25, 23, 1], [26, 24, 1], [38, 54, 1], [39, 55, 1], [40, 56, 1], ] ), } expected_identificationtypes = { PERIODIC_1D: np.array([[2]]), PERIODIC_2D: np.array([[1, 1, 1, 2]]), PERIODIC_3D: np.array([[2]]), } expected_field_data = { PERIODIC_1D: {}, PERIODIC_2D: {"outer": [3, 1], "periodic": [4, 1]}, PERIODIC_3D: {"outer": [6, 2], "default": [3, 2]}, } @pytest.mark.parametrize("netgen_mesh", [PERIODIC_1D, PERIODIC_2D, PERIODIC_3D]) def test_advanced(netgen_mesh, tmp_path): mesh = meshio.read(str(netgen_mesh_directory / netgen_mesh)) p = tmp_path / f"{netgen_mesh}_out.vol" mesh.write(p) mesh_out = meshio.read(p) assert np.all( mesh.info["netgen:identifications"] == expected_identifications[netgen_mesh] ) assert np.all( mesh.info["netgen:identifications"] == mesh_out.info["netgen:identifications"] ) assert np.all( mesh.info["netgen:identificationtypes"] == expected_identificationtypes[netgen_mesh] ) assert np.all( mesh.info["netgen:identificationtypes"] == mesh_out.info["netgen:identificationtypes"] ) for kk, vv in mesh.field_data.items(): assert np.all(vv == expected_field_data[netgen_mesh][kk]) assert np.all(vv == mesh_out.field_data[kk]) for cd, cd_out in zip( mesh.cell_data["netgen:index"], mesh_out.cell_data["netgen:index"] ): assert np.all(cd == cd_out) tests/test_neuroglancer.py000066400000000000000000000015641456244072500163340ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ # helpers.empty_mesh, helpers.tri_mesh ], ) def test_neuroglancer(mesh, tmp_path): def writer(*args, **kwargs): return meshio.neuroglancer.write(*args, **kwargs) # 32bit only helpers.write_read(tmp_path, writer, meshio.neuroglancer.read, mesh, 1.0e-8) @pytest.mark.parametrize("filename, ref_sum, ref_num_cells", [("simple1", 20, 4)]) def test_reference_file(filename, ref_sum, ref_num_cells): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "neuroglancer" / filename mesh = meshio.read(filename, "neuroglancer") tol = 1.0e-5 s = np.sum(mesh.points) assert abs(s - ref_sum) < tol * abs(ref_sum) assert len(mesh.cells[0].data) == ref_num_cells tests/test_obj.py000066400000000000000000000020641456244072500144160ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.tri_mesh, helpers.quad_mesh, helpers.tri_quad_mesh, helpers.polygon_mesh, ], ) def test_obj(mesh, tmp_path): for k, c in enumerate(mesh.cells): mesh.cells[k] = meshio.CellBlock(c.type, c.data.astype(np.int32)) helpers.write_read(tmp_path, meshio.obj.write, meshio.obj.read, mesh, 1.0e-12) @pytest.mark.skip("Fails point data consistency check.") @pytest.mark.parametrize( "filename, ref_sum, ref_num_cells", [("elephav.obj", 3.678372172450000e05, 1148)] ) def test_reference_file(filename, ref_sum, ref_num_cells): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "obj" / filename mesh = meshio.read(filename) tol = 1.0e-5 s = np.sum(mesh.points) assert abs(s - ref_sum) < tol * abs(ref_sum) assert mesh.cells[0].type == "triangle" assert len(mesh.cells[0].data) == ref_num_cells tests/test_off.py000066400000000000000000000006761456244072500144250ustar00rootroot00000000000000import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ # helpers.empty_mesh, helpers.tri_mesh ], ) def test_io(mesh, tmp_path): helpers.write_read(tmp_path, meshio.off.write, meshio.off.read, mesh, 1.0e-15) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.off") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.off") tests/test_permas.py000066400000000000000000000014541456244072500151350ustar00rootroot00000000000000import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh, # helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, # helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, ], ) def test_io(mesh, tmp_path): helpers.write_read(tmp_path, meshio.permas.write, meshio.permas.read, mesh, 1.0e-15) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.post") helpers.generic_io(tmp_path / "test.post.gz") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.post") helpers.generic_io(tmp_path / "test.0.post.gz") tests/test_ply.py000066400000000000000000000036541456244072500144560ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ # helpers.empty_mesh, helpers.tri_mesh, helpers.quad_mesh, helpers.tri_quad_mesh, helpers.add_point_data(helpers.tri_mesh, 1, dtype=int), helpers.add_point_data(helpers.tri_mesh, 1, dtype=float), helpers.line_mesh, helpers.polygon_mesh, # helpers.add_cell_data(helpers.tri_mesh, [("a", (), np.float64)]), # helpers.add_cell_data(helpers.tri_mesh, [("a", (2,), np.float64)]), # helpers.add_cell_data(helpers.tri_mesh, [("a", (3,), np.float64)]), ], ) @pytest.mark.parametrize("binary", [False, True]) def test_ply(mesh, binary, tmp_path): def writer(*args, **kwargs): return meshio.ply.write(*args, binary=binary, **kwargs) for k, c in enumerate(mesh.cells): mesh.cells[k] = meshio.CellBlock(c.type, c.data.astype(np.int32)) helpers.write_read(tmp_path, writer, meshio.ply.read, mesh, 1.0e-12) @pytest.mark.parametrize( "filename, ref_sum, ref_num_cells", [ ("bun_zipper_res4.ply", 3.414583969116211e01, 948), ("tet.ply", 6, 4), ], ) def test_reference_file(filename, ref_sum, ref_num_cells): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "ply" / filename mesh = meshio.read(filename) tol = 1.0e-2 s = np.sum(mesh.points) assert abs(s - ref_sum) < tol * abs(ref_sum) assert len(mesh.get_cells_type("triangle")) == ref_num_cells @pytest.mark.parametrize("binary", [False, True]) def test_no_cells(binary): import io vertices = np.random.random((30, 3)) mesh = meshio.Mesh(vertices, []) file = io.BytesIO() mesh.write(file, "ply", binary=binary) mesh2 = meshio.read(io.BytesIO(file.getvalue()), "ply") assert np.array_equal(mesh.points, mesh2.points) assert len(mesh2.cells) == 0 tests/test_public.py000066400000000000000000000001621456244072500151170ustar00rootroot00000000000000import meshio def test_public_attributes(): # Just make sure this is here meshio.extension_to_filetypes tests/test_stl.py000066400000000000000000000010011456244072500144340ustar00rootroot00000000000000import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [helpers.empty_mesh, helpers.tri_mesh], ) @pytest.mark.parametrize( "binary, tol", [ (False, 1.0e-15), # binary STL only operates in single precision (True, 1.0e-8), ], ) def test_stl(mesh, binary, tol, tmp_path): def writer(*args, **kwargs): return meshio.stl.write(*args, binary=binary, **kwargs) helpers.write_read(tmp_path, writer, meshio.stl.read, mesh, tol) tests/test_su2.py000066400000000000000000000021161456244072500143530ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers test_set = [ # helpers.empty_mesh, helpers.tri_mesh_2d, helpers.tet_mesh, helpers.hex_mesh, ] this_dir = pathlib.Path(__file__).resolve().parent @pytest.mark.parametrize("mesh", test_set) def test(mesh, tmp_path): helpers.write_read(tmp_path, meshio.su2.write, meshio.su2.read, mesh, 1.0e-15) @pytest.mark.parametrize( "filename, ref_num_cells, ref_num_points,ref_num_unique_tags,sum_tags", [("square.su2", 16, 9, 4, 20), ("mixgrid.su2", 30, 16, 6, 62)], ) def test_structured( filename, ref_num_cells, ref_num_points, ref_num_unique_tags, sum_tags ): filename = this_dir / "meshes" / "su2" / filename mesh = meshio.read(filename) assert sum(len(block.data) for block in mesh.cells) == ref_num_cells assert len(mesh.points) == ref_num_points all_tags = np.concatenate([tags for tags in mesh.cell_data["su2:tag"]]) assert sum(all_tags) == sum_tags all_unique_tags = np.unique(all_tags) assert len(all_unique_tags) == ref_num_unique_tags + 1 tests/test_svg.py000066400000000000000000000005451456244072500144450ustar00rootroot00000000000000import pytest import meshio from . import helpers test_set = [ helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh, helpers.tri_mesh_2d, helpers.quad_mesh, ] @pytest.mark.parametrize("mesh", test_set) def test(mesh, tmp_path): filepath = tmp_path / "out.svg" meshio.write_points_cells(filepath, mesh.points, mesh.cells) tests/test_tecplot.py000066400000000000000000000044371456244072500153240ustar00rootroot00000000000000import pathlib from copy import deepcopy import numpy as np import pytest import meshio from . import helpers @pytest.mark.parametrize( "mesh", [ # helpers.empty_mesh, helpers.tri_mesh, helpers.quad_mesh, # Those two tests suddenly started failing on gh-actions. No idea why. # TODO reinstate # helpers.tet_mesh, # helpers.hex_mesh ], ) def test(mesh, tmp_path): helpers.write_read( tmp_path, meshio.tecplot.write, meshio.tecplot.read, mesh, 1.0e-15 ) @pytest.mark.parametrize( "filename", ["quad_zone_comma.tec", "quad_zone_space.tec", "quad_zone_multivar.tec"] ) def test_comma_space(filename, tmp_path): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "tecplot" / filename mesh = meshio.read(filename) helpers.write_read( tmp_path, meshio.tecplot.write, meshio.tecplot.read, mesh, 1.0e-15 ) def test_varlocation(tmp_path): # Test that VARLOCATION is correctly written and read depending on the # number of point and cell data. writer = meshio.tecplot.write reader = meshio.tecplot.read mesh = deepcopy(helpers.tri_mesh) num_points = len(mesh.points) num_cells = sum(len(c.data) for c in mesh.cells) # Add point data: no VARLOCATION mesh.point_data["one"] = np.ones(num_points) helpers.write_read(tmp_path, writer, reader, mesh, 1.0e-15) # Add cell data: VARLOCATION = ([5] = CELLCENTERED) mesh.cell_data["two"] = [np.ones(num_cells) * 2.0] helpers.write_read(tmp_path, writer, reader, mesh, 1.0e-15) # Add point data: VARLOCATION = ([6] = CELLCENTERED) mesh.point_data["three"] = np.ones(num_points) * 3.0 helpers.write_read(tmp_path, writer, reader, mesh, 1.0e-15) # Add cell data: VARLOCATION = ([6-7] = CELLCENTERED) mesh.cell_data["four"] = [np.ones(num_cells) * 4.0] helpers.write_read(tmp_path, writer, reader, mesh, 1.0e-15) # Add point data: VARLOCATION = ([7-8] = CELLCENTERED) mesh.point_data["five"] = np.ones(num_points) * 5.0 helpers.write_read(tmp_path, writer, reader, mesh, 1.0e-15) # Add cell data: VARLOCATION = ([7-9] = CELLCENTERED) mesh.cell_data["six"] = [np.ones(num_cells) * 6.0] helpers.write_read(tmp_path, writer, reader, mesh, 1.0e-15) tests/test_tetgen.py000066400000000000000000000014441456244072500151330ustar00rootroot00000000000000import pathlib import pytest import meshio from . import helpers test_set = [ # helpers.empty_mesh, helpers.tet_mesh ] @pytest.mark.parametrize("mesh", test_set) def test(mesh, tmp_path): helpers.write_read( tmp_path, meshio.tetgen.write, meshio.tetgen.read, mesh, 1.0e-15, extension=".node", ) @pytest.mark.parametrize( "filename, point_ref_sum, cell_ref_sum", [("mesh.ele", 12, 373)] ) def test_point_cell_refs(filename, point_ref_sum, cell_ref_sum): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "tetgen" / filename mesh = meshio.read(filename) assert mesh.point_data["tetgen:ref"].sum() == point_ref_sum assert mesh.cell_data["tetgen:ref"][0].sum() == cell_ref_sum tests/test_ugrid.py000066400000000000000000000151501456244072500147560ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers this_dir = pathlib.Path(__file__).resolve().parent @pytest.mark.parametrize( "mesh", [ helpers.empty_mesh, helpers.tri_mesh, helpers.quad_mesh, # helpers.tri_quad_mesh, helpers.quad_tri_mesh, helpers.tet_mesh, helpers.hex_mesh, ], ) @pytest.mark.parametrize( "accuracy,ext", [ (1.0e-7, ".ugrid"), (1.0e-15, ".b8.ugrid"), (1.0e-7, ".b4.ugrid"), (1.0e-15, ".lb8.ugrid"), (1.0e-7, ".lb4.ugrid"), (1.0e-15, ".r8.ugrid"), (1.0e-7, ".r4.ugrid"), (1.0e-15, ".lr8.ugrid"), (1.0e-7, ".lr4.ugrid"), ], ) def test_io(mesh, accuracy, ext, tmp_path): helpers.write_read( tmp_path, meshio.ugrid.write, meshio.ugrid.read, mesh, accuracy, ext ) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.lb8.ugrid") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.lb8.ugrid") # sphere_mixed.1.lb8.ugrid and hch_strct.4.lb8.ugrid created # using the codes from http://cfdbooks.com @pytest.mark.parametrize( "filename, ref_num_points, ref_num_triangle, ref_num_quad, ref_num_wedge, ref_num_tet, ref_num_hex, ref_tag_counts", [ ( "sphere_mixed.1.lb8.ugrid", 3270, 864, 0, 3024, 9072, 0, {1: 432, 2: 216, 3: 216}, ), ("hch_strct.4.lb8.ugrid", 306, 12, 178, 96, 0, 144, {1: 15, 2: 15, 3: 160}), ], ) def test_reference_file( filename, ref_num_points, ref_num_triangle, ref_num_quad, ref_num_wedge, ref_num_tet, ref_num_hex, ref_tag_counts, ): filename = this_dir / "meshes" / "ugrid" / filename mesh = meshio.read(filename) assert mesh.points.shape[0] == ref_num_points assert mesh.points.shape[1] == 3 ugrid_meshio_id = { "triangle": None, "quad": None, "tetra": None, "pyramid": None, "wedge": None, "hexahedron": None, } for i, cell_block in enumerate(mesh.cells): if cell_block.type in ugrid_meshio_id: ugrid_meshio_id[cell_block.type] = i # validate element counts if ref_num_triangle > 0: c = mesh.cells[ugrid_meshio_id["triangle"]] assert c.data.shape == (ref_num_triangle, 3) else: assert ugrid_meshio_id["triangle"] is None if ref_num_quad > 0: c = mesh.cells[ugrid_meshio_id["quad"]] assert c.data.shape == (ref_num_quad, 4) else: assert ugrid_meshio_id["quad"] is None if ref_num_tet > 0: c = mesh.cells[ugrid_meshio_id["tetra"]] assert mesh.cells[1].data.shape == (ref_num_tet, 4) else: assert ugrid_meshio_id["tetra"] is None if ref_num_wedge > 0: c = mesh.cells[ugrid_meshio_id["wedge"]] assert c.data.shape == (ref_num_wedge, 6) else: assert ugrid_meshio_id["wedge"] is None if ref_num_hex > 0: c = mesh.cells[ugrid_meshio_id["hexahedron"]] assert c.data.shape == (ref_num_hex, 8) else: assert ugrid_meshio_id["hexahedron"] is None # validate boundary tags # gather tags all_tags = [] for k, c in enumerate(mesh.cells): if c.type not in ["triangle", "quad"]: continue all_tags.append(mesh.cell_data["ugrid:ref"][k]) all_tags = np.concatenate(all_tags) # validate against known values unique, counts = np.unique(all_tags, return_counts=True) tags = dict(zip(unique, counts)) assert tags.keys() == ref_tag_counts.keys() for key in tags.keys(): assert tags[key] == ref_tag_counts[key] def _tet_volume(cell): """ Evaluate the volume of a tetrahedron using the value of the deteminant | a_x a_y a_z 1 | | b_x b_y b_z 1 | | c_x c_y c_z 1 | | d_x d_y d_z 1 | """ t = np.ones((4, 1)) cell = np.append(cell, t, axis=1) vol = -np.linalg.det(cell) / 6.0 return vol def _pyramid_volume(cell): """ Evaluate pyramid volume by splitting it into two tetrahedra """ tet0 = cell[[0, 1, 3, 4]] tet1 = cell[[1, 2, 3, 4]] vol = 0.0 vol += _tet_volume(tet0) vol += _tet_volume(tet1) return vol # ugrid node ordering is the same for all elements except the pyramids. In order to make # sure we got it right read a cube split into pyramids and evaluate its volume @pytest.mark.parametrize("filename, volume,accuracy", [("pyra_cube.ugrid", 1.0, 1e-15)]) def test_volume(filename, volume, accuracy): filename = this_dir / "meshes" / "ugrid" / filename mesh = meshio.read(filename) assert mesh.cells[0].type == "pyramid" assert mesh.cells[0].data.shape == (6, 5) vol = 0.0 for _cell in mesh.cells[0].data: cell = np.array([mesh.points[i] for i in _cell]) v = _pyramid_volume(cell) vol += v assert np.isclose(vol, 1.0, accuracy) def _triangle_area(cell): """ Evaluate triangle area using cross product of two edge vectors """ u = cell[0] - cell[1] v = cell[0] - cell[2] return np.linalg.norm(np.cross(u, v)) / 2.0 def _quad_area(cell): """ Evaluate triangle area using cross product of two edge vectors """ tri1 = cell[[0, 1, 2]] tri2 = cell[[2, 3, 0]] return _triangle_area(tri1) + _triangle_area(tri2) # Test whether any of the surface elements is connected in the wrong way @pytest.mark.parametrize( "filename, area_tria_ref,area_quad_ref,accuracy", [("hch_strct.4.lb8.ugrid", 9587.10463, 74294.529256, 1e-5)], ) def test_area(filename, area_tria_ref, area_quad_ref, accuracy): filename = this_dir / "meshes" / "ugrid" / filename mesh = meshio.read(filename) ugrid_meshio_id = { "triangle": None, "quad": None, "tetra": None, "pyramid": None, "wedge": None, "hexahedron": None, } for i, cell_block in enumerate(mesh.cells): if cell_block.type in ugrid_meshio_id: ugrid_meshio_id[cell_block.type] = i tria = mesh.cells[ugrid_meshio_id["triangle"]] total_tri_area = 0 for _cell in tria.data: cell = np.array([mesh.points[i] for i in _cell]) a = _triangle_area(cell) total_tri_area += a assert np.isclose(total_tri_area, area_tria_ref, accuracy) quad = mesh.cells[ugrid_meshio_id["quad"]] total_quad_area = 0 for _cell in quad.data: cell = np.array([mesh.points[i] for i in _cell]) a = _quad_area(cell) total_quad_area += a assert np.isclose(total_quad_area, area_quad_ref, accuracy) tests/test_vtk.py000066400000000000000000000076341456244072500144600ustar00rootroot00000000000000import pathlib from functools import partial import numpy as np import pytest import meshio from . import helpers test_set = { # helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh_2d, helpers.tri_mesh, helpers.tri_mesh_one_cell, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, helpers.polygon_mesh, helpers.pyramid_mesh, helpers.wedge_mesh, helpers.add_point_data(helpers.tri_mesh, 1), helpers.add_point_data(helpers.tri_mesh, 2), helpers.add_point_data(helpers.tri_mesh, 3), # VTK files float data is always stored in big endian helpers.add_cell_data(helpers.tri_mesh, [("a", (), ">f8")]), helpers.add_cell_data(helpers.tri_mesh, [("a", (2,), ">f8")]), helpers.add_cell_data(helpers.tri_mesh, [("a", (3,), ">f8")]), helpers.add_cell_data( helpers.add_point_data(helpers.tri_mesh_2d, 2), [("a", (2,), ">f8")] ), } @pytest.mark.parametrize("mesh", test_set.union({helpers.lagrange_high_order_mesh})) @pytest.mark.parametrize("binary", [True, False]) def test(mesh, binary, tmp_path): def writer(*args, **kwargs): return meshio.vtk.write(*args, binary=binary, **kwargs) helpers.write_read(tmp_path, writer, meshio.vtk.read, mesh, 1.0e-15) @pytest.mark.parametrize("mesh", test_set) @pytest.mark.parametrize("binary", [True, False]) def test_vtk42(mesh, binary, tmp_path): def writer(*args, **kwargs): return meshio.vtk.write(*args, binary=binary, fmt_version="4.2", **kwargs) helpers.write_read(tmp_path, writer, meshio.vtk.read, mesh, 1.0e-15) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.vtk") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.vtk") @pytest.mark.parametrize( "filename, ref_sum, ref_num_cells", [("rbc_001.vtk", 0.00031280518, 996)] ) @pytest.mark.parametrize("binary", [False, True]) def test_reference_file(filename, ref_sum, ref_num_cells, binary, tmp_path): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "vtk" / filename mesh = meshio.read(filename) tol = 1.0e-2 s = np.sum(mesh.points) assert abs(s - ref_sum) < tol * ref_sum assert mesh.cells[0].type == "triangle" assert len(mesh.cells[0].data) == ref_num_cells writer = partial(meshio.vtk.write, binary=binary) helpers.write_read(tmp_path, writer, meshio.vtk.read, mesh, 1.0e-15) @pytest.mark.parametrize( "filename, ref_cells, ref_num_cells, ref_num_pnt", [ ("00_image.vtk", "quad", 81, 100), ("01_image.vtk", "hexahedron", 72, 147), ("02_structured.vtk", "hexahedron", 72, 147), ("03_rectilinear.vtk", "hexahedron", 72, 147), ("04_rectilinear.vtk", "quad", 27, 40), ("05_rectilinear.vtk", "quad", 27, 40), ("06_unstructured.vtk", "hexahedron", 12, 42), ("gh-935.vtk", "triangle", 2, 6), ], ) def test_structured(filename, ref_cells, ref_num_cells, ref_num_pnt): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "vtk" / filename mesh = meshio.read(filename) assert len(mesh.cells) == 1 assert ref_cells == mesh.cells[0].type assert len(mesh.cells[0].data) == ref_num_cells assert len(mesh.points) == ref_num_pnt def test_pathlike(): this_dir = pathlib.Path(__file__).resolve().parent meshio.read(this_dir / "meshes" / "vtk" / "rbc_001.vtk") @pytest.mark.parametrize( "filename, ref_num_points, ref_num_cells", [("06_color_scalars.vtk", 5, 2)] ) def test_color_scalars(filename, ref_num_points, ref_num_cells): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "vtk" / filename mesh = meshio.read(filename) assert len(mesh.points) == ref_num_points assert len(mesh.cells) == ref_num_cells tests/test_vtu.py000066400000000000000000000050621456244072500144630ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers test_set = [ # helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh, helpers.tri_mesh_one_cell, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.tri_quad_mesh, helpers.polygon_mesh, helpers.polygon_mesh_one_cell, helpers.polygon2_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, helpers.pyramid_mesh, helpers.wedge_mesh, helpers.polyhedron_mesh, helpers.lagrange_high_order_mesh, helpers.add_point_data(helpers.tri_mesh, 1), helpers.add_point_data(helpers.tri_mesh, 2), helpers.add_point_data(helpers.tri_mesh, 3), helpers.add_cell_data(helpers.tri_mesh, [("a", (), np.float64)]), helpers.add_cell_data(helpers.tri_quad_mesh, [("a", (), np.float64)]), helpers.add_cell_data(helpers.tri_mesh, [("a", (2,), np.float32)]), helpers.add_cell_data(helpers.tri_mesh, [("b", (3,), np.float64)]), helpers.add_cell_data(helpers.polygon_mesh, [("a", (), np.float32)]), helpers.add_cell_data(helpers.polyhedron_mesh, [("a", (2,), np.float32)]), ] @pytest.mark.parametrize("mesh", test_set) @pytest.mark.parametrize( "data_type", [(False, None), (True, None), (True, "lzma"), (True, "zlib")] ) def test(mesh, data_type, tmp_path): binary, compression = data_type def writer(*args, **kwargs): return meshio.vtu.write(*args, binary=binary, compression=compression, **kwargs) # ASCII files are only meant for debugging, VTK stores only 11 digits # tol = 1.0e-15 if binary else 1.0e-10 helpers.write_read(tmp_path, writer, meshio.vtu.read, mesh, tol) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.vtu") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.vtu") @pytest.mark.parametrize( "filename, ref_cells, ref_num_cells, ref_num_pnt", [ ("00_raw_binary.vtu", "tetra", 162, 64), ("01_raw_binary_int64.vtu", "tetra", 162, 64), ("02_raw_compressed.vtu", "tetra", 162, 64), ], ) def test_read_from_file(filename, ref_cells, ref_num_cells, ref_num_pnt): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "vtu" / filename mesh = meshio.read(filename) assert len(mesh.cells) == 1 assert ref_cells == mesh.cells[0].type assert len(mesh.cells[0].data) == ref_num_cells assert len(mesh.points) == ref_num_pnt tests/test_wkt.py000066400000000000000000000015411456244072500144500ustar00rootroot00000000000000import pathlib import numpy as np import pytest import meshio from . import helpers # TODO reenable @pytest.mark.skip() @pytest.mark.parametrize( "mesh", [ # helpers.empty_mesh, helpers.tri_mesh ], ) def test_wkt(mesh, tmp_path): helpers.write_read(tmp_path, meshio.wkt.write, meshio.wkt.read, mesh, 1.0e-12) @pytest.mark.parametrize( "filename, ref_sum, ref_num_cells", [("simple.wkt", 4, 2), ("whitespaced.wkt", 3.2, 2)], ) def test_reference_file(filename, ref_sum, ref_num_cells): this_dir = pathlib.Path(__file__).resolve().parent filename = this_dir / "meshes" / "wkt" / filename mesh = meshio.read(filename) tol = 1.0e-5 s = np.sum(mesh.points) assert abs(s - ref_sum) < tol * abs(ref_sum) assert mesh.cells[0].type == "triangle" assert len(mesh.cells[0].data) == ref_num_cells tests/test_xdmf.py000066400000000000000000000066671456244072500146170ustar00rootroot00000000000000import numpy as np import pytest import meshio from . import helpers test_set_full = [ helpers.empty_mesh, helpers.line_mesh, helpers.tri_mesh, helpers.line_tri_mesh, helpers.tri_mesh_2d, helpers.triangle6_mesh, helpers.quad_mesh, helpers.quad8_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.tet10_mesh, helpers.hex_mesh, helpers.hex20_mesh, helpers.pyramid_mesh, helpers.wedge_mesh, helpers.add_point_data(helpers.tri_mesh, 1), helpers.add_cell_data(helpers.tri_mesh, [("a", (), np.float64)]), ] test_set_reduced = [ helpers.tri_mesh, helpers.tri_mesh_2d, helpers.quad_mesh, helpers.tri_quad_mesh, helpers.tet_mesh, helpers.hex_mesh, helpers.add_point_data(helpers.tri_mesh, 1), helpers.add_cell_data(helpers.tri_mesh, [("a", (), np.float64)]), ] @pytest.mark.parametrize("mesh", test_set_full) @pytest.mark.parametrize( "kwargs0", [ {"data_format": "XML"}, {"data_format": "Binary"}, {"data_format": "HDF", "compression": None}, {"data_format": "HDF", "compression": "gzip"}, ], ) def test_xdmf3(mesh, kwargs0, tmp_path): def write(*args, **kwargs): return meshio.xdmf.write(*args, **{**kwargs0, **kwargs}) helpers.write_read(tmp_path, write, meshio.xdmf.read, mesh, 1.0e-14) def test_generic_io(tmp_path): helpers.generic_io(tmp_path / "test.xdmf") # With additional, insignificant suffix: helpers.generic_io(tmp_path / "test.0.xdmf") def test_time_series(): # write the data filename = "out.xdmf" with meshio.xdmf.TimeSeriesWriter(filename) as writer: writer.write_points_cells(helpers.tri_mesh_2d.points, helpers.tri_mesh_2d.cells) n = helpers.tri_mesh_2d.points.shape[0] times = np.linspace(0.0, 1.0, 5) point_data = [ { "phi": np.full(n, t), "u": np.full(helpers.tri_mesh_2d.points.shape, t), } for t in times ] for t, pd in zip(times, point_data): writer.write_data( t, point_data=pd, cell_data={"a": {"triangle": [3.0, 4.2]}} ) # read it back in with meshio.xdmf.TimeSeriesReader(filename) as reader: points, cells = reader.read_points_cells() for k in range(reader.num_steps): t, pd, cd = reader.read_data(k) assert np.abs(times[k] - t) < 1.0e-12 for key, value in pd.items(): assert np.all(np.abs(value - point_data[k][key]) < 1.0e-12) # def test_information_xdmf(): # mesh_out = meshio.Mesh( # np.array( # [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]] # ) # / 3, # [("triangle", np.array([[0, 1, 2], [0, 2, 3]]))], # field_data={ # "bottom": np.array([1, 1]), # "right": np.array([2, 1]), # "top": np.array([3, 1]), # "left": np.array([4, 1]), # }, # ) # # write the data # points, cells, field_data = mesh_out.points, mesh_out.cells, mesh_out.field_data # # assert cells[0].type == "triangle" # meshio.write( # "mesh.xdmf", # meshio.Mesh(points=points, cells=[cells[0]], field_data=field_data), # ) # # # read it back in # mesh_in = meshio.read("mesh.xdmf") # assert len(mesh_in.field_data) == len(mesh_out.field_data) if __name__ == "__main__": test_time_series() tools/000077500000000000000000000000001456244072500122275ustar00rootroot00000000000000tools/paraview-meshio-plugin.py000066400000000000000000000151101456244072500171730ustar00rootroot00000000000000import numpy as np from paraview.util.vtkAlgorithm import ( VTKPythonAlgorithmBase, smdomain, smhint, smproperty, smproxy, ) from vtkmodules.numpy_interface import dataset_adapter as dsa from vtkmodules.vtkCommonDataModel import vtkUnstructuredGrid import meshio paraview_plugin_version = meshio.__version__ vtk_to_meshio_type = meshio._vtk_common.vtk_to_meshio_type meshio_to_vtk_type = meshio._vtk_common.meshio_to_vtk_type meshio_input_filetypes = list(meshio._helpers.reader_map.keys()) meshio_extensions = [ext[1:] for ext in meshio.extension_to_filetypes.keys()] meshio_input_filetypes = ["automatic"] + meshio_input_filetypes @smproxy.reader( name="meshio reader", extensions=meshio_extensions, file_description="meshio-supported files", support_reload=False, ) class MeshioReader(VTKPythonAlgorithmBase): def __init__(self): VTKPythonAlgorithmBase.__init__( self, nInputPorts=0, nOutputPorts=1, outputType="vtkUnstructuredGrid" ) self._filename = None self._file_format = None @smproperty.stringvector(name="FileName") @smdomain.filelist() @smhint.filechooser( extensions=meshio_extensions, file_description="meshio-supported files" ) def SetFileName(self, filename): if self._filename != filename: self._filename = filename self.Modified() @smproperty.stringvector(name="StringInfo", information_only="1") def GetStrings(self): return meshio_input_filetypes @smproperty.stringvector(name="FileFormat", number_of_elements="1") @smdomain.xml( """ """ ) def SetFileFormat(self, file_format): # Automatically deduce input format if file_format == "automatic": file_format = None if self._file_format != file_format: self._file_format = file_format self.Modified() def RequestData(self, request, inInfoVec, outInfoVec): output = dsa.WrapDataObject(vtkUnstructuredGrid.GetData(outInfoVec)) # Use meshio to read the mesh mesh = meshio.read(self._filename, self._file_format) points, cells = mesh.points, mesh.cells # Points if points.shape[1] == 2: points = np.hstack([points, np.zeros((len(points), 1))]) output.SetPoints(points) # CellBlock, adapted from test/legacy_writer.py cell_types = np.array([], dtype=np.ubyte) cell_offsets = np.array([], dtype=int) cell_conn = np.array([], dtype=int) for meshio_type, data in cells: vtk_type = meshio_to_vtk_type[meshio_type] ncells, npoints = data.shape cell_types = np.hstack( [cell_types, np.full(ncells, vtk_type, dtype=np.ubyte)] ) offsets = len(cell_conn) + (1 + npoints) * np.arange(ncells, dtype=int) cell_offsets = np.hstack([cell_offsets, offsets]) conn = np.hstack( [npoints * np.ones((ncells, 1), dtype=int), data] ).flatten() cell_conn = np.hstack([cell_conn, conn]) output.SetCells(cell_types, cell_offsets, cell_conn) # Point data for name, array in mesh.point_data.items(): output.PointData.append(array, name) # Cell data for name, data in mesh.cell_data.items(): array = np.concatenate(data) output.CellData.append(array, name) # Field data for name, array in mesh.field_data.items(): output.FieldData.append(array, name) return 1 @smproxy.writer( name="meshio Writer", extensions=meshio_extensions, file_description="meshio-supported files", support_reload=False, ) @smproperty.input(name="Input", port_index=0) @smdomain.datatype(dataTypes=["vtkUnstructuredGrid"], composite_data_supported=False) class MeshioWriter(VTKPythonAlgorithmBase): def __init__(self): VTKPythonAlgorithmBase.__init__( self, nInputPorts=1, nOutputPorts=0, inputType="vtkUnstructuredGrid" ) self._filename = None @smproperty.stringvector(name="FileName", panel_visibility="never") @smdomain.filelist() def SetFileName(self, filename): if self._filename != filename: self._filename = filename self.Modified() def RequestData(self, request, inInfoVec, outInfoVec): mesh = dsa.WrapDataObject(vtkUnstructuredGrid.GetData(inInfoVec[0])) # Read points points = np.asarray(mesh.GetPoints()) # Read cells # Adapted from test/legacy_reader.py cell_conn = mesh.GetCells() cell_offsets = mesh.GetCellLocations() cell_types = mesh.GetCellTypes() cells_dict = {} for vtk_cell_type in np.unique(cell_types): offsets = cell_offsets[cell_types == vtk_cell_type] ncells = len(offsets) npoints = cell_conn[offsets[0]] array = np.empty((ncells, npoints), dtype=int) for i in range(npoints): array[:, i] = cell_conn[offsets + i + 1] cells_dict[vtk_to_meshio_type[vtk_cell_type]] = array cells = [meshio.CellBlock(key, cells_dict[key]) for key in cells_dict] # Read point and field data # Adapted from test/legacy_reader.py def _read_data(data): out = {} for i in range(data.VTKObject.GetNumberOfArrays()): name = data.VTKObject.GetArrayName(i) array = np.asarray(data.GetArray(i)) out[name] = array return out point_data = _read_data(mesh.GetPointData()) field_data = _read_data(mesh.GetFieldData()) # Read cell data cell_data_flattened = _read_data(mesh.GetCellData()) cell_data = {} for name, array in cell_data_flattened.items(): cell_data[name] = [] for cell_type in cells_dict: vtk_cell_type = meshio_to_vtk_type[cell_type] mask_cell_type = cell_types == vtk_cell_type cell_data[name].append(array[mask_cell_type]) # Use meshio to write mesh meshio.write_points_cells( self._filename, points, cells, point_data=point_data, cell_data=cell_data, field_data=field_data, ) return 1 def Write(self): self.Modified() self.Update() tox.ini000066400000000000000000000012011456244072500123740ustar00rootroot00000000000000# usage: # tox --> default, runs pytest # tox -e fmt --> format the code and README # tox -e lint --> check code formatting and lint the code [tox] envlist = py3 isolated_build = True [testenv] deps = pytest pytest-codeblocks >= 0.12.1 pytest-cov # pytest-randomly extras = all commands = pytest {posargs} --codeblocks [testenv:fmt] skip_install = True commands = isort . black . blacken-docs README.md deps = black isort blacken-docs [testenv:lint] skip_install = True commands = isort --check . black --check . flake8 . deps = black flake8 isort