Skip to content
Snippets Groups Projects
vtkfile.hh 12.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifndef DUNE_GFE_VTKFILE_HH
    #define DUNE_GFE_VTKFILE_HH
    
    
    #include <vector>
    #include <fstream>
    
    #if HAVE_TINYXML2
    // For VTK file reading
    #include <tinyxml2.h>
    #endif
    
    #include <dune/common/fvector.hh>
    
    // For parallel infrastructure stuff:
    #include <dune/grid/io/file/vtk.hh>
    
    
    namespace Dune {
    
      namespace GFE {
    
        /** \brief A class representing a VTK file, but independent from the Dune grid interface
         *
         * This file is supposed to represent an abstraction layer in between the pure XML used for VTK files,
         * and the VTKWriter from dune-grid, which knows about grids.  In theory, the dune-grid VTKWriter
         * could use this class to simplify its own code.  More importantly, the VTKFile class allows to
         * write files containing second-order geometries, which is currently not possible with the dune-grid
         * VTKWriter.
         */
        class VTKFile
        {
    
        public:
    
          /** \brief Write the file to disk */
          void write(const std::string& filename) const
          {
    
            int argc = 0;
            char** argv;
            Dune::MPIHelper& mpiHelper = Dune::MPIHelper::instance(argc,argv);
    
    
            std::string fullfilename = filename + ".vtu";
    
            // Prepend rank and communicator size to the filename, if there are more than one process
    
            if (mpiHelper.size() > 1)
              fullfilename = getParallelPieceName(filename, "", mpiHelper.rank(), mpiHelper.size());
    
    
            // Write the pvtu file that ties together the different parts
    
            if (mpiHelper.size() > 1 && mpiHelper.rank()==0)
    
              std::ofstream pvtuOutFile(getParallelName(filename, "", mpiHelper.size()));
    
              Dune::VTK::PVTUWriter writer(pvtuOutFile, Dune::VTK::unstructuredGrid);
    
              writer.beginMain();
    
              writer.beginPointData();
              writer.addArray<float>("director0", 3);
              writer.addArray<float>("director1", 3);
              writer.addArray<float>("director2", 3);
              writer.addArray<float>("zCoord", 1);
              writer.endPointData();
    
    
              writer.beginCellData();
              writer.addArray<float>("mycelldata", 1);
              writer.endCellData();
    
    
              // dump point coordinates
              writer.beginPoints();
              writer.addArray<float>("Coordinates", 3);
              writer.endPoints();
    
    
              for (int i=0; i<mpiHelper.size(); i++)
              writer.addPiece(getParallelPieceName(filename, "", i, mpiHelper.size()));
    
    
              // finish main section
              writer.endMain();
            }
    
            std::ofstream outFile(fullfilename);
    
            // Write header
            outFile << "<?xml version=\"1.0\"?>" << std::endl;
            outFile << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">" << std::endl;
            outFile << "  <UnstructuredGrid>" << std::endl;
            outFile << "    <Piece NumberOfCells=\"" << cellOffsets_.size() << "\" NumberOfPoints=\"" << points_.size() << "\">" << std::endl;
    
            // Write vertex coordinates
            outFile << "      <Points>" << std::endl;
    
            {  // extra parenthesis to control destruction of the pointsWriter object
              Dune::VTK::AsciiDataArrayWriter<float> pointsWriter(outFile, "Coordinates", 3, Dune::Indent(4));
              for (size_t i=0; i<points_.size(); i++)
                for (int j=0; j<3; j++)
                  pointsWriter.write(points_[i][j]);
            }  // destructor of pointsWriter objects writes trailing </DataArray> to file
    
            outFile << "      </Points>" << std::endl;
    
            // Write elements
            outFile << "      <Cells>" << std::endl;
    
            {  // extra parenthesis to control destruction of the cellConnectivityWriter object
              Dune::VTK::AsciiDataArrayWriter<int> cellConnectivityWriter(outFile, "connectivity", 1, Dune::Indent(4));
              for (size_t i=0; i<cellConnectivity_.size(); i++)
                cellConnectivityWriter.write(cellConnectivity_[i]);
    
            {  // extra parenthesis to control destruction of the writer object
              Dune::VTK::AsciiDataArrayWriter<int> cellOffsetsWriter(outFile, "offsets", 1, Dune::Indent(4));
              for (size_t i=0; i<cellOffsets_.size(); i++)
                cellOffsetsWriter.write(cellOffsets_[i]);
            }
    
            {  // extra parenthesis to control destruction of the writer object
              Dune::VTK::AsciiDataArrayWriter<unsigned int> cellTypesWriter(outFile, "types", 1, Dune::Indent(4));
              for (size_t i=0; i<cellTypes_.size(); i++)
                cellTypesWriter.write(cellTypes_[i]);
            }
    
            //////////////////////////////////////////////////
            //   Point data
            //////////////////////////////////////////////////
    
            outFile << "      <PointData Scalars=\"zCoord\" Vectors=\"director0\">" << std::endl;
    
            // Z coordinate for better visualization of wrinkles
    
            {  // extra parenthesis to control destruction of the writer object
              Dune::VTK::AsciiDataArrayWriter<float> zCoordWriter(outFile, "zCoord", 1, Dune::Indent(4));
              for (size_t i=0; i<zCoord_.size(); i++)
                zCoordWriter.write(zCoord_[i]);
            }
    
    
            // The three director fields
            for (size_t i=0; i<3; i++)
            {
    
              Dune::VTK::AsciiDataArrayWriter<float> directorWriter(outFile, "director" + std::to_string(i), 3, Dune::Indent(4));
    
              for (size_t j=0; j<directors_[i].size(); j++)
    
                for (int k=0; k<3; k++)
                  directorWriter.write(directors_[i][j][k]);
    
            //////////////////////////////////////////////////
            //   Cell data
            //////////////////////////////////////////////////
    
            if (cellData_.size() > 0)
            {
              outFile << "      <CellData>" << std::endl;
    
              {  // extra parenthesis to control destruction of the writer object
                Dune::VTK::AsciiDataArrayWriter<float> cellDataWriter(outFile, "mycelldata", 1, Dune::Indent(4));
                for (size_t i=0; i<cellData_.size(); i++)
                  cellDataWriter.write(cellData_[i]);
              }
    
              outFile << "      </CellData>" << std::endl;
            }
    
            //////////////////////////////////////////////////
            //   Write footer
            //////////////////////////////////////////////////
    
            outFile << "    </Piece>" << std::endl;
            outFile << "  </UnstructuredGrid>" << std::endl;
            outFile << "</VTKFile>" << std::endl;
    
    
          }
    
    
          /** \brief Read a VTKFile object from a file
           *
           * This method uses TinyXML2.  If you do not have TinyXML2 installed the code will simply throw a NotImplemented exception.
           */
          void read(const std::string& filename)
          {
    
            int argc = 0;
            char** argv;
            Dune::MPIHelper& mpiHelper = Dune::MPIHelper::instance(argc,argv);
    
    
            std::string fullfilename = filename + ".vtu";
    
            // Prepend rank and communicator size to the filename, if there are more than one process
    
            if (mpiHelper.size() > 1)
              fullfilename = getParallelPieceName(filename, "", mpiHelper.rank(), mpiHelper.size());
    
    #if ! HAVE_TINYXML2
            DUNE_THROW(Dune::NotImplemented, "You need TinyXML2 for vtk file reading!");
    #else
            tinyxml2::XMLDocument doc;
    
            if (int error = doc.LoadFile(fullfilename.c_str()) != tinyxml2::XML_SUCCESS)
            {
              std::cout << "Error: " << error << std::endl;
    
              DUNE_THROW(Dune::IOError, "Couldn't open the file '" << fullfilename << "'");
    
    
            // Get number of cells and number of points
            tinyxml2::XMLElement* pieceElement = doc.FirstChildElement( "VTKFile" )->FirstChildElement( "UnstructuredGrid" )->FirstChildElement( "Piece" );
    
            int numberOfCells;
            int numberOfPoints;
            pieceElement->QueryIntAttribute( "NumberOfCells", &numberOfCells );
            pieceElement->QueryIntAttribute( "NumberOfPoints", &numberOfPoints );
    
            //////////////////////////////////
            //  Read point coordinates
            //////////////////////////////////
            points_.resize(numberOfPoints);
            tinyxml2::XMLElement* pointsElement = pieceElement->FirstChildElement( "Points" )->FirstChildElement( "DataArray" );
    
            std::stringstream coordsStream(pointsElement->GetText());
    
            double inDouble;
            size_t i=0;
            while (coordsStream >> inDouble)
            {
              points_[i/3][i%3] = inDouble;
              i++;
            }
    
            ///////////////////////////////////
            //  Read cells
            ///////////////////////////////////
            tinyxml2::XMLElement* cellsElement = pieceElement->FirstChildElement( "Cells" )->FirstChildElement( "DataArray" );
    
            for (int i=0; i<3; i++)
            {
              int inInt;
              if (cellsElement->Attribute("Name", "connectivity"))
              {
                std::stringstream connectivityStream(cellsElement->GetText());
                while (connectivityStream >> inInt)
                  cellConnectivity_.push_back(inInt);
              }
              if (cellsElement->Attribute("Name", "offsets"))
              {
                std::stringstream offsetsStream(cellsElement->GetText());
                while (offsetsStream >> inInt)
                  cellOffsets_.push_back(inInt);
              }
              if (cellsElement->Attribute("Name", "types"))
              {
                std::stringstream typesStream(cellsElement->GetText());
                while (typesStream >> inInt)
                  cellTypes_.push_back(inInt);
              }
    
              cellsElement = cellsElement->NextSiblingElement();
            }
    
            /////////////////////////////////////
            //  Read point data
            /////////////////////////////////////
    
            tinyxml2::XMLElement* pointDataElement = pieceElement->FirstChildElement( "PointData" )->FirstChildElement( "DataArray" );
    
            for (int i=0; i<4; i++)
            {
              size_t j=0;
              std::stringstream directorStream(pointDataElement->GetText());
              if (pointDataElement->Attribute("Name", "director0"))
              {
                directors_[0].resize(numberOfPoints);
                while (directorStream >> inDouble)
                {
                  directors_[0][j/3][j%3] = inDouble;
                  j++;
                }
              }
              if (pointDataElement->Attribute("Name", "director1"))
              {
                directors_[1].resize(numberOfPoints);
                while (directorStream >> inDouble)
                {
                  directors_[1][j/3][j%3] = inDouble;
                  j++;
                }
              }
              if (pointDataElement->Attribute("Name", "director2"))
              {
                directors_[2].resize(numberOfPoints);
                while (directorStream >> inDouble)
                {
                  directors_[2][j/3][j%3] = inDouble;
                  j++;
                }
              }
    
              pointDataElement = pointDataElement->NextSiblingElement();
            }
    #endif
          }
    
    
          std::vector<Dune::FieldVector<double,3> > points_;
    
          std::vector<int> cellConnectivity_;
    
          std::vector<int> cellOffsets_;
    
          std::vector<int> cellTypes_;
    
          std::vector<double> zCoord_;
    
    
          std::vector<double> cellData_;
    
    
          std::array<std::vector<Dune::FieldVector<double,3> >, 3 > directors_;
    
        private:
    
          /** \brief Extend filename to contain communicator rank and size
           *
           * Copied from dune-grid vtkwriter.hh
           */
          static std::string getParallelPieceName(const std::string& name,
                                                  const std::string& path,
                                                  int commRank, int commSize)
          {
            std::ostringstream s;
            if(path.size() > 0) {
              s << path;
              if(path[path.size()-1] != '/')
                s << '/';
            }
            s << 's' << std::setw(4) << std::setfill('0') << commSize << '-';
            s << 'p' << std::setw(4) << std::setfill('0') << commRank << '-';
            s << name;
            if (true) //(GridType::dimension > 1)
              s << ".vtu";
            else
              s << ".vtp";
            return s.str();
          }
    
    
          /** \brief Extend filename to contain communicator rank and size
           *
           * Copied from dune-grid vtkwriter.hh
           */
          static std::string getParallelName(const std::string& name,
                                             const std::string& path,
                                             int commSize)
          {
            std::ostringstream s;
            if(path.size() > 0) {
              s << path;
              if(path[path.size()-1] != '/')
                s << '/';
            }
            s << 's' << std::setw(4) << std::setfill('0') << commSize << '-';
            s << name;
            if (true) //(GridType::dimension > 1)
              s << ".pvtu";
            else
              s << ".pvtp";
            return s.str();
          }
    
        };
    
      }
    
    }