CFD Online Discussion Forums

CFD Online Discussion Forums (https://www.cfd-online.com/Forums/)
-   Main CFD Forum (https://www.cfd-online.com/Forums/main/)
-   -   Paraview .vtr files in binary (https://www.cfd-online.com/Forums/main/255353-paraview-vtr-files-binary.html)

djr4cfd April 3, 2024 11:10

Paraview .vtr files in binary
 
Dear all,
I am trying to write my output files in vtr format and the following gives me a correct output file in ASCII.

Code:

#include <iostream>
#include <fstream>
#include <cmath>

// Function to calculate phi = sin(x) * cos(y)
double phi(double x, double y) {
    return sin(x) * cos(y);
}

int main() {
    int n = 10; // Size of the mesh (10x10)
    double step = 1.0 / (n - 1); // Step size
   
    std::ofstream outfile("output.vtr");
   
    // Writing the header
    outfile << "<?xml version=\"1.0\"?>\n";
    outfile << "<VTKFile type=\"RectilinearGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n";
    outfile << "<RectilinearGrid WholeExtent=\"0 " << n-1 << " 0 " << n-1 << " 0 0\">\n";
    outfile << "<Piece Extent=\"0 " << n-1 << " 0 " << n-1 << " 0 0\">\n";
    // Writing the scalar data (phi)
    outfile << "<PointData>\n";
    outfile << "<DataArray type=\"Float64\" Name=\"phi\" NumberOfComponents=\"1\" format=\"ascii\">\n";
    for (int j = 0; j < n; ++j) {
        for (int i = 0; i < n; ++i) {
            double x = i * step;
            double y = j * step;
            outfile << phi(x, y) << " ";
        }
    }
    outfile << "\n</DataArray>\n";
    outfile << "</PointData>\n";
    // Writing the coordinates
    outfile << "<Coordinates>\n";
    outfile << "<DataArray type=\"Float64\" Name=\"X_COORDINATES\" NumberOfComponents=\"1\" format=\"ascii\">\n";
    for (int i = 0; i < n; ++i) {
        outfile << i * step << " ";
    }
    outfile << "\n</DataArray>\n";
    outfile << "<DataArray type=\"Float64\" Name=\"Y_COORDINATES\" NumberOfComponents=\"1\" format=\"ascii\">\n";
    for (int j = 0; j < n; ++j) {
        outfile << j * step << " ";
    }
    outfile << "\n</DataArray>\n"; 
    outfile << "<DataArray type=\"Float64\" Name=\"Z_COORDINATES\" NumberOfComponents=\"1\" format=\"ascii\">\n";
    outfile << "0.0 \n";
    outfile << "</DataArray>\n";
    outfile << "</Coordinates>\n";
   
    // Closing tags
    outfile << "</Piece>\n";
    outfile << "</RectilinearGrid>\n";
    outfile << "</VTKFile>\n";
   
    outfile.close();
   
    std::cout << "Output file generated: output.vtr\n";
   
    return 0;
}


To get output file in BINARY, I tried the following:
Code:

#include <iostream>
#include <fstream>
#include <cmath>

// Function to calculate phi = sin(x) * cos(y)
double phi(double x, double y) {
    return sin(x) * cos(y);
}

int main() {
    int n = 10; // Size of the mesh (10x10)
    double step = 1.0 / (n - 1); // Step size
   
    std::ofstream outfile("output.vtr");
   
    double A[n][n];
    double xx[n];
    double yy[n];
   
    for (int j = 0; j < n; ++j) {
        for (int i = 0; i < n; ++i) {
            double x = i * step;
            double y = j * step;
            //outfile << phi(x, y) << " ";
            A[i][j]= phi(x, y);
        }
    }
   
    for (int i = 0; i < n; ++i) {
        xx[i] =i * step;
    }
   
    for (int j = 0; j < n; ++j) {
        yy[j] =j * step;
    }
   
    // Writing the header
    outfile << "<?xml version=\"1.0\"?>\n";
    outfile << "<VTKFile type=\"RectilinearGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n";
    outfile << "<RectilinearGrid WholeExtent=\"0 " << n-1 << " 0 " << n-1 << " 0 0\">\n";
    outfile << "<Piece Extent=\"0 " << n-1 << " 0 " << n-1 << " 0 0\">\n";
    // Writing the scalar data (phi)
    outfile << "<PointData>\n";
    outfile << "<DataArray type=\"Int64\" Name=\"phi\" NumberOfComponents=\"1\" format=\"binary\">\n";
    for (int j = 0; j < n; ++j) {
        for (int i = 0; i < n; ++i) {
            outfile.write(reinterpret_cast<const char*>(&A[i][j]), sizeof(double));
        }
    }
    outfile << "\n</DataArray>\n";
    outfile << "</PointData>\n";
    // Writing the coordinates
    outfile << "<Coordinates>\n";
    outfile << "<DataArray type=\"Int64\" Name=\"X_COORDINATES\" NumberOfComponents=\"1\" format=\"binary\">\n";
    for (int i = 0; i < n; ++i) {
        outfile.write(reinterpret_cast<const char*>(&xx[i]), sizeof(double));
    }
    outfile << "\n</DataArray>\n";
    outfile << "<DataArray type=\"Int64\" Name=\"Y_COORDINATES\" NumberOfComponents=\"1\" format=\"binary\">\n";
    for (int j = 0; j < n; ++j) {
        outfile.write(reinterpret_cast<const char*>(&yy[j]), sizeof(double));
    }
    outfile << "\n</DataArray>\n"; 
    outfile << "<DataArray type=\"Int64\" Name=\"Z_COORDINATES\" NumberOfComponents=\"1\" format=\"binary\">\n";
    double z =0.0;
    outfile.write(reinterpret_cast<const char*>(&z), sizeof(double));
    //outfile << "0.0 \n";
    outfile << "\n</DataArray>\n";
    outfile << "</Coordinates>\n";
   
    // Closing tags
    outfile << "</Piece>\n";
    outfile << "</RectilinearGrid>\n";
    outfile << "</VTKFile>\n";
   
    outfile.close();
   
    std::cout << "Output file generated: output.vtr\n";
   
    return 0;
}

The generated output is not correctly read by Paraview. It gives me the following error.

ERROR: In /builds/gitlab-kitware-sciviz-ci/build/superbuild/paraview/src/VTK/IO/XMLParser/vtkXMLParser.cxx, line 379
vtkXMLDataParser (0x1659c570): Error parsing XML in stream at line 7, column 0, byte index 255: not well-formed (invalid token)

ERROR: In /builds/gitlab-kitware-sciviz-ci/build/superbuild/paraview/src/VTK/IO/XML/vtkXMLReader.cxx, line 521
vtkXMLRectilinearGridReader (0x17dda5a0): Error parsing input file. ReadXMLInformation aborting.

I am using a Ubuntu system; byte_order is LittleEndian and using g++ compiler. Paraview version is 5.10.1.

Can anyone help me fix this. A similar example for writing binary vtr files using c++ will also help.

djr4cfd April 7, 2024 02:12

Successfully ported to legacy VTK. But xml vtk binary is still unaccomplished
 
Hi all,
I have successfully implemented the output file writing in binary using the legacy vtk format. For this, I had to use byte swap to BigEndian. The code is as follows.

Code:


#include <iostream>
#include <fstream>
#include <cmath>

template <typename T>
void SwapEnd(T& var)
{
  char* varArray = reinterpret_cast<char*>(&var);
  for(long i = 0; i < static_cast<long>(sizeof(var)/2); i++)
    std::swap(varArray[sizeof(var) - 1 - i],varArray[i]);
}

int main()
{
    int n = 10; // Size of the mesh (10x10)
    double step = 1.0 / (n - 1); // Step size

    double A[n][n];
    double xx[n];
    double yy[n];
   
    for (int j = 0; j < n; j++) {
        for (int i = 0; i < n; i++) {
            double x = i * step;
            double y = j * step;
            A[i][j]= sin(x) * cos(y);
        }
    }
   
    for (int i = 0; i < n; i++) {
        xx[i] =i * step;
    }
   
    for (int j = 0; j < n; j++) {
        yy[j] =j * step;
    }

  std::ofstream vtkstream;
  vtkstream.open("outputBinary.vtk", std::ios::out | std::ios::binary);
  if (vtkstream) {
    vtkstream<<"# vtk DataFile Version 2.0"<<"\n";
    vtkstream<<"Phi=sin(x)"<<"\n";
    vtkstream<<"BINARY"<<"\n";
    vtkstream<<"DATASET RECTILINEAR_GRID"<<std::endl;
    vtkstream<<"DIMENSIONS " << n << " " << n << " 1"<<std::endl;
    vtkstream<<"X_COORDINATES " << n << " double"<<std::endl;
    //for (int i = 0; i < n; i++) {
    for (unsigned int i = 0; i < n; i++) {
        SwapEnd(xx[i]);
        vtkstream.write((char*)&xx[i], sizeof(double));
        //vtkstream<< xx[i] << " ";
    }
    vtkstream<<"\nY_COORDINATES " << n << " double"<<std::endl;
    //for (int j = 0; j < n; j++) {
    for (unsigned int j = 0; j < n; j++) {
        SwapEnd(yy[j]);
        vtkstream.write((char*)&yy[j], sizeof(double));
        //vtkstream<< yy[j] << " ";
    }
    vtkstream<<"\nZ_COORDINATES " << 1 << " double"<<std::endl;
    double zz = 0.0;
    SwapEnd(zz);
    vtkstream.write((char*)&zz, sizeof(double));
    //vtkstream<< "0.0" << "\n";
    vtkstream<<"POINT_DATA " << n*n << std::endl;
    vtkstream<<"SCALARS " << "Phi " << " double 1" <<std::endl;
    vtkstream<<"LOOKUP_TABLE default" <<std::endl;
    for (int j = 0; j < n; j++) {
        for (int i = 0; i < n; i++) {
            SwapEnd(A[i][j]);
            vtkstream.write((char*)&A[i][j], sizeof(double));
        }
    }
    vtkstream.close();
  }
 
  else {
    std::cout<<"ERROR"<<std::endl;
  }
  return 0;
}



I desperately want to convert this to XML VTK in binary. Specifically, I wish to understand the following.

1. format ="binary"
This involves base64 encoding. But I am not able to understand how to do this in c++ for an array of double.

2. format="appended"
< AppendedData encoding="raw">
_NNNNData
</AppendedData>

Here I am not understanding how to specify NNNN.

Experts, please help me with this.

djr4cfd April 8, 2024 02:50

Working code in c++ to generate xml vtk files in appended raw binary
 
After lots and lots of effort, I found out how to write in binary.

Some reverse engineering helped me. We can load ascii files in paraview and use file>save data to generate binary files.

I am sharing the code below.

Code:

#include <iostream>
#include <fstream>
#include <cmath>

int main() {
    int n = 10; // Size of the mesh (10x10)
    double step = 1.0 / (n - 1); // Step size
   
    double A[n][n];
    double xx[n];
    double yy[n];
   
    for (int i = 0; i < n; i++) {
        xx[i] =i * step;
    }
   
    for (int j = 0; j < n; j++) {
        yy[j] =j * step;
    }
   
    double zz =0.0;

    for (int j = 0; j < n; j++) {
        for (int i = 0; i < n; i++) {
            A[i][j]= sin(xx[i]) * cos(yy[j]);
        }
    }

    // Size of each array
    int N1 = n*n*sizeof(double); // size of A in bytes
    int N2 = n*sizeof(double);  // size of xx in bytes
    int N3 = n*sizeof(double);  // size of yy in bytes
    int N4 = 1*sizeof(double);  // size of zz in bytes

    // Offsets
    int offset1 = 0;
    int offset2 = offset1 + sizeof(double) + N1;
    int offset3 = offset2 + sizeof(double) + N2;
    int offset4 = offset3 + sizeof(double) + N3;
   
    std::ofstream outfile("output_binaryAppended.vtr", std::ios::out | std::ios::binary);
   
    if (outfile) {
        // Writing the header
        outfile << "<?xml version=\"1.0\"?>\n";
        outfile << "<VTKFile type=\"RectilinearGrid\" version=\"1.0\" header_type=\"UInt64\" byte_order=\"LittleEndian\">\n";
        outfile << "<RectilinearGrid WholeExtent=\"0 " << n-1 << " 0 " << n-1 << " 0 0\">\n";
        outfile << "<Piece Extent=\"0 " << n-1 << " 0 " << n-1 << " 0 0\">\n";
        // Writing the scalar data (phi)
        outfile << "<PointData>\n";
        outfile << "<DataArray type=\"Float64\" Name=\"phi\" format=\"appended\" offset=\"" << offset1 <<"\">\n";
        outfile << "</DataArray>\n";
        outfile << "</PointData>\n";
        // Writing the coordinates
        outfile << "<Coordinates>\n";
        outfile << "<DataArray type=\"Float64\" Name=\"X_COORDINATES\" format=\"appended\" offset=\"" << offset2 <<"\">\n";
        outfile << "</DataArray>\n";
        outfile << "<DataArray type=\"Float64\" Name=\"Y_COORDINATES\" format=\"appended\" offset=\"" << offset3 <<"\">\n";
        outfile << "</DataArray>\n";
        outfile << "<DataArray type=\"Float64\" Name=\"Z_COORDINATES\" format=\"appended\" offset=\"" << offset4 <<"\">\n";
        outfile << "</DataArray>\n";
        outfile << "</Coordinates>\n";
        // Closing tags
        outfile << "</Piece>\n";
        outfile << "</RectilinearGrid>\n";
        // Appended Data
        outfile << "<AppendedData encoding=\"raw\">\n";
        outfile << "_";
        outfile.write((char*)&N1, sizeof(double));
        for (int j = 0; j < n; j++) {
            for (int i = 0; i < n; i++) {
                outfile.write((char*)&A[i][j], sizeof(double));
            }
        }
        outfile.write((char*)&N2, sizeof(double));
        for (int i = 0; i < n; i++) {
            outfile.write((char*)&xx[i], sizeof(double));
        }
        outfile.write((char*)&N3, sizeof(double));
        for (int j = 0; j < n; j++) {
            outfile.write((char*)&yy[j], sizeof(double));
        }
        outfile.write((char*)&N4, sizeof(double));
        outfile.write((char*)&zz, sizeof(double));
       
        outfile << "\n</AppendedData>\n";
        // Final closing tags
        outfile << "</VTKFile>\n";
        outfile.close();
    }
 
    else {
        std::cout<<"ERROR"<<std::endl;
    }
   
    std::cout << "Output file generated: output_binaryAppended.vtr\n";

    return 0;
}

Hope this helps someone some day!!!


All times are GMT -4. The time now is 07:00.