phmkopp / vtu11

Vtu11 is a small C++ header-only library to write unstructured grids using the vtu file format

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Vtu11

Vtu11 is a small C++ header-only library to write unstructured grids using the vtu file format. It keeps the mess of dealing with file writing in different formats away from you. Currently it does not add any features for setting up the required data structure because this vastly differs based on the context in which vtu11 is used.

You can download a single header version in the latest release.

Serial example

#include "vtu11/vtu11.hpp"

int main( )
{
    // Create data for 3x2 quad mesh: (x, y, z) coordinates of mesh vertices
    std::vector<double> points
    {
        0.0, 0.0, 0.5,    0.0, 0.3, 0.5,    0.0, 0.7, 0.5,    0.0, 1.0, 0.5, // 0,  1,  2,  3
        0.5, 0.0, 0.5,    0.5, 0.3, 0.5,    0.5, 0.7, 0.5,    0.5, 1.0, 0.5, // 4,  5,  6,  7
        1.0, 0.0, 0.5,    1.0, 0.3, 0.5,    1.0, 0.7, 0.5,    1.0, 1.0, 0.5  // 8,  9, 10, 11
    };

    // Vertex indices of all cells
    std::vector<vtu11::VtkIndexType> connectivity
    {
        0,  4,  5,  1, // 0
        1,  5,  6,  2, // 1
        2,  6,  7,  3, // 2
        4,  8,  9,  5, // 3
        5,  9, 10,  6, // 4
        6, 10, 11,  7  // 5
    };

    // Separate cells in connectivity array
    std::vector<vtu11::VtkIndexType> offsets { 4, 8, 12, 16, 20, 24 };

    // Cell types of each cell, see [1]
    std::vector<vtu11::VtkCellType> types { 9, 9, 9, 9, 9, 9 };

    // Create small proxy mesh type
    vtu11::Vtu11UnstructuredMesh mesh { points, connectivity, offsets, types };

    // Create some data associated to points and cells
    std::vector<double> pointData { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0 };
    std::vector<double> cellData { 3.2, 4.3, 5.4, 6.5, 7.6, 8.7 };

    // Create tuples with (name, association, number of components) for each data set
    std::vector<vtu11::DataSetInfo> dataSetInfo
    {
        { "Temperature", vtu11::DataSetType::PointData, 1 },
        { "Conductivity", vtu11::DataSetType::CellData, 1 },
    };

    // Write data to .vtu file using Ascii format
    vtu11::writeVtu( "test.vtu", mesh, dataSetInfo, { pointData, cellData }, "Ascii" );
}

Available writers are (not case sensitive):

  • "Ascii"
  • "Base64Inline"
  • "Base64Appended"
  • "RawBinary"
  • "RawBinaryCompressed"

Comments:

  • RawCompressedBinary requires zlib to be enabled by defining the VTU11_ENABLE_ZLIB proprocessor symbol. Otherwise the uncompressed version is used instead. Compiled executables also have to be linked to zlib.
  • Compressing data takes more time than writing more data uncompressed
  • Ascii produces surprisingly small files, is nice to debug, but is rather slow to read in Paraview. Archiving ascii .vtu files using a standard zip tool (for example) produces decently small file sizes.
  • Writing raw binary data breakes the xml standard. To still produce valid xml files you can use base64 encoding, at the cost of having about 30% times larger files.
  • Both raw binary modes use appended format

How to include in your project

The lazy way of using vtu11 is to use the single header version provided with the latest release. If you want to use the project as it is, then you need to add it to the directories that the compiler searches for include files and compile using (at least) the C++ 11 standard. Let's say you are working in a Linux environment where you clone the vtu11 project and create an example.cpp next to it. Using for example g++ you compile as follows:

g++ -Ivtu11 --std=c++11 -o example example.cpp

If you want to use compressed vtu output, then you can add the VTU11_ENABLE_ZLIB definition and link to zlib:

g++ -Ivtu11 -DVTU11_ENABLE_ZLIB --std=c++11 -o example example.cpp -lz 

Alternatively, you can use CMake and add vtu11 as subdirectory. This will automatically set up the vtu11::vtu11 interface target with the correct include path and compile flags. Your CMakeLists.txt could then simply look like this:

cmake_minimum_required( VERSION 3.12 )

project( example LANGUAGES CXX )

add_subdirectory( vtu11 )

add_executable( example example.cpp )

target_link_libraries( example PRIVATE vtu11::vtu11 )

Now you can create a build directory, compile the project and run the example.

Parallel example

The pvtu format is used in combination with the vtu format. The mesh needs to be partitioned before it is given to vtu11. Each part of the mesh is written to a vtu file, and the pvtu file contains the references to those files. Overlapping entities like ghost nodes or cells can be added too if needed for e.g. other cells.

#include "vtu11/vtu11.hpp"

int main( )
{
    // Split the 3x2 cells from serial example in two 3x1 partitions

    // Row 0 and 1
    std::vector<double> points0
    {
        0.0, 0.0, 0.5,    0.0, 0.3, 0.5,    0.0, 0.7, 0.5,    0.0, 1.0, 0.5, // 0,  1,  2,  3
        0.5, 0.0, 0.5,    0.5, 0.3, 0.5,    0.5, 0.7, 0.5,    0.5, 1.0, 0.5, // 4,  5,  6,  7
    };

    // Row 1 and 2
    std::vector<double> points1
    {                                                                        // Original indices:
        0.5, 0.0, 0.5,    0.5, 0.3, 0.5,    0.5, 0.7, 0.5,    0.5, 1.0, 0.5, // 4,  5,  6,  7
        1.0, 0.0, 0.5,    1.0, 0.3, 0.5,    1.0, 0.7, 0.5,    1.0, 1.0, 0.5  // 8,  9, 10, 11
    };

    // Original cells 0, 1 and 2
    std::vector<vtu11::VtkIndexType> connectivity0
    {
        0,  4,  5,  1, // 0
        1,  5,  6,  2, // 1
        2,  6,  7,  3, // 2
    };

    // Original cells 3, 4, and 5 (now using local vertex indices)
    std::vector<vtu11::VtkIndexType> connectivity1
    {
        0,  4,  5,  1, // 3
        1,  5,  6,  2, // 4
        2,  6,  7,  3, // 5
    };

    std::vector<vtu11::VtkIndexType> offsets0 { 4, 8, 12 };
    std::vector<vtu11::VtkIndexType> offsets1 { 4, 8, 12 };

    std::vector<vtu11::VtkCellType> types0 { 9, 9, 9 };
    std::vector<vtu11::VtkCellType> types1 { 9, 9, 9 };

    // Create one proxy for each partition
    vtu11::Vtu11UnstructuredMesh meshPartition0 { points0, connectivity0, offsets0, types0 };
    vtu11::Vtu11UnstructuredMesh meshPartition1 { points1, connectivity1, offsets1, types1 };

    // Because vertices are duplicated also point data is duplicated
    std::vector<double> pointData0 { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 };
    std::vector<double> pointData1 { 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0 };

    std::vector<double> cellData0 { 3.2, 4.3, 5.4 };
    std::vector<double> cellData1 { 6.5, 7.6, 8.7 };

    // These hold for all partitions
    std::vector<vtu11::DataSetInfo> dataSetInfo
    {
        { "Temperature", vtu11::DataSetType::PointData, 1 },
        { "Conductivity", vtu11::DataSetType::CellData, 1 },
    };

    std::vector<vtu11::DataSetData> dataSetData0 { pointData0, cellData0 };
    std::vector<vtu11::DataSetData> dataSetData1 { pointData1, cellData1 };

    size_t numberOfFiles = 2;

    std::string path = ".";
    std::string basename = "test";

    // First write .pvtu file and create folder for .vtu partitions. This must be
    // done only once (e.g. on MPI rank 0 or before an omp parallel section).
    vtu11::writePVtu( path, basename, dataSetInfo, numberOfFiles );

    // Write two .vtu partitions. This can happen in parallel as there are no dependencies.
    // Note that the `writePVtu` must have completed before calling this function
    vtu11::writePartition( path, basename, meshPartition0, dataSetInfo, dataSetData0, 0, "RawBinary" );
    vtu11::writePartition( path, basename, meshPartition1, dataSetInfo, dataSetData1, 1, "RawBinary" );
}

The folder structure for the example above would look like this (in folder ./):

test.pvtu
test
  |-- test_0.vtu
  |-- test_1.vtu

Resources

[1] https://vtk.org/wp-content/uploads/2015/04/file-formats.pdf

About

Vtu11 is a small C++ header-only library to write unstructured grids using the vtu file format

License:BSD 3-Clause "New" or "Revised" License


Languages

Language:C++ 98.0%Language:CMake 1.7%Language:Shell 0.2%