Loading CMakeLists.txt +4 −0 Original line number Diff line number Diff line Loading @@ -160,6 +160,10 @@ if( DEFINED ENV{CI_JOB_NAME} OR ${CMAKE_GENERATOR} STREQUAL "Ninja" ) endif() endif() # add the filesystem library to all targets # https://en.cppreference.com/w/cpp/filesystem link_libraries( stdc++fs ) # gtest has to be built before we add the MPI flags if( ${WITH_TESTS} OR ${WITH_MATRIX_TESTS} ) enable_testing() Loading src/TNL/Meshes/Writers/PVTUWriter.h 0 → 100644 +107 −0 Original line number Diff line number Diff line /*************************************************************************** PVTUWriter.h - description ------------------- begin : Apr 17, 2020 copyright : (C) 2020 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ // Implemented by: Jakub Klinkovský #pragma once #include <TNL/Meshes/Writers/VTUWriter.h> #include <TNL/Meshes/DistributedMeshes/DistributedMesh.h> namespace TNL { namespace Meshes { namespace Writers { // NOTE: Mesh should be the local mesh type, not DistributedMesh template< typename Mesh > class PVTUWriter { using HeaderType = std::uint64_t; public: using MeshRealType = typename Mesh::RealType; using IndexType = typename Mesh::GlobalIndexType; PVTUWriter() = delete; PVTUWriter( std::ostream& str, VTK::FileFormat format = VTK::FileFormat::zlib_compressed ) : str(str), format(format) {} // If desired, cycle and time of the simulation can put into the file. This follows the instructions at // http://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files void writeMetadata( std::int32_t cycle = -1, double time = -1 ); template< int EntityDimension = Mesh::getMeshDimension() > void writeEntities( const DistributedMeshes::DistributedMesh< Mesh >& distributedMesh ); template< int EntityDimension = Mesh::getMeshDimension() > void writeEntities( const Mesh& mesh, const unsigned GhostLevel = 0, const unsigned MinCommonVertices = 0 ); template< typename ValueType > void writePPointData( const String& name, const int numberOfComponents = 1 ); template< typename ValueType > void writePCellData( const String& name, const int numberOfComponents = 1 ); template< typename ValueType > void writePDataArray( const String& name, const int numberOfComponents = 1 ); // add a single piece and return its source path // (useful for sequential writing, e.g. from tnl-decompose-mesh) std::string addPiece( const String& mainFileName, const unsigned subdomainIndex ); // add all pieces and return the source path for the current rank // (useful for parallel writing) template< typename Communicator > std::string addPiece( const String& mainFileName, const typename Communicator::CommunicationGroup group ); ~PVTUWriter(); protected: void writeHeader( const unsigned GhostLevel = 0, const unsigned MinCommonVertices = 0 ); void writePoints( const Mesh& mesh ); void writeFooter(); std::ostream& str; VTK::FileFormat format; // indicator if the <VTKFile> tag is open bool vtkfileOpen = false; // indicators if a <PCellData> tag is open or closed bool pCellDataOpen = false; bool pCellDataClosed = false; // indicators if a <PPointData> tag is open or closed bool pPointDataOpen = false; bool pPointDataClosed = false; void openPCellData(); void closePCellData(); void openPPointData(); void closePPointData(); }; } // namespace Writers } // namespace Meshes } // namespace TNL #include <TNL/Meshes/Writers/PVTUWriter.hpp> src/TNL/Meshes/Writers/PVTUWriter.hpp 0 → 100644 +255 −0 Original line number Diff line number Diff line /*************************************************************************** PVTUWriter.hpp - description ------------------- begin : Apr 17, 2020 copyright : (C) 2020 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ // Implemented by: Jakub Klinkovský #pragma once #include <experimental/filesystem> #include <TNL/Meshes/Writers/PVTUWriter.h> namespace TNL { namespace Meshes { namespace Writers { template< typename Mesh > void PVTUWriter< Mesh >::writeMetadata( int cycle, double time ) { if( ! vtkfileOpen ) throw std::logic_error("writeMetadata has to be called after writeEntities in case of the PVTU format, otherwise header attributes would be left unset." ); if( cycle >= 0 || time >= 0 ) str << "<FieldData>\n"; if( cycle >= 0 ) { str << "<DataArray type=\"Int32\" Name=\"CYCLE\" NumberOfTuples=\"1\" format=\"ascii\">" << cycle << "</DataArray>\n"; } if( time >= 0 ) { str.precision( std::numeric_limits< double >::digits10 ); str << "<DataArray type=\"Float64\" Name=\"TIME\" NumberOfTuples=\"1\" format=\"ascii\">" << time << "</DataArray>\n"; } if( cycle >= 0 || time >= 0 ) str << "</FieldData>\n"; } template< typename Mesh > template< int EntityDimension > void PVTUWriter< Mesh >::writeEntities( const DistributedMeshes::DistributedMesh< Mesh >& distributedMesh ) { writeEntities< EntityDimension >( distributedMesh.getLocalMesh(), distributedMesh.getGhostLevels(), Mesh::Config::dualGraphMinCommonVertices ); } template< typename Mesh > template< int EntityDimension > void PVTUWriter< Mesh >::writeEntities( const Mesh& mesh, const unsigned GhostLevel, const unsigned MinCommonVertices ) { if( ! vtkfileOpen ) writeHeader( GhostLevel, MinCommonVertices ); // write points writePoints( mesh ); } template< typename Mesh > template< typename ValueType > void PVTUWriter< Mesh >::writePPointData( const String& name, const int numberOfComponents ) { if( ! vtkfileOpen ) throw std::logic_error("The VTKFile has not been opened yet - call writeEntities first."); openPPointData(); writePDataArray< ValueType >( name, numberOfComponents ); } template< typename Mesh > template< typename ValueType > void PVTUWriter< Mesh >::writePCellData( const String& name, const int numberOfComponents ) { if( ! vtkfileOpen ) throw std::logic_error("The VTKFile has not been opened yet - call writeEntities first."); openPCellData(); writePDataArray< ValueType >( name, numberOfComponents ); } template< typename Mesh > template< typename ValueType > void PVTUWriter< Mesh >::writePDataArray( const String& name, const int numberOfComponents ) { if( numberOfComponents != 0 && numberOfComponents != 1 && numberOfComponents != 3 ) throw std::logic_error("Unsupported numberOfComponents parameter: " + std::to_string(numberOfComponents)); str << "<PDataArray type=\"" << VTK::getTypeName( ValueType{} ) << "\" "; str << "Name=\"" << name << "\" "; str << "NumberOfComponents=\"" << numberOfComponents << "\"/>\n"; } template< typename Mesh > std::string PVTUWriter< Mesh >::addPiece( const String& mainFileName, const unsigned subdomainIndex ) { if( ! mainFileName.endsWith( ".pvtu" ) ) throw std::logic_error("The mainFileName parameter must be the name of the " ".pvtu file (i.e., it must have the .pvtu suffix)."); // close PCellData and PPointData sections closePCellData(); closePPointData(); namespace fs = std::experimental::filesystem; // get the basename of the main file (filename without extension) const fs::path mainPath = mainFileName.getString(); const fs::path basename = mainPath.stem(); // create subdirectory for subdomains const fs::path subdirectory = mainPath.parent_path() / basename; fs::create_directory( subdirectory ); // write <Piece> tag const std::string subfile = "subdomain." + std::to_string(subdomainIndex) + ".vtu"; const std::string source = basename / subfile; str << "<Piece Source=\"" << source << "\"/>\n"; // return subfile path return subdirectory / subfile; } template< typename Mesh > template< typename Communicator > std::string PVTUWriter< Mesh >::addPiece( const String& mainFileName, const typename Communicator::CommunicationGroup group ) { std::string source; for( int i = 0; i < Communicator::GetSize( group ); i++ ) { const std::string s = addPiece( mainFileName, i ); if( i == Communicator::GetRank( group ) ) source = s; } return source; } template< typename Mesh > void PVTUWriter< Mesh >::writeHeader( const unsigned GhostLevel, const unsigned MinCommonVertices ) { str << "<?xml version=\"1.0\"?>\n"; str << "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\""; if( isLittleEndian() ) str << " byte_order=\"LittleEndian\""; else str << " byte_order=\"BigEndian\""; str << " header_type=\"" << VTK::getTypeName( HeaderType{} ) << "\""; #ifdef HAVE_ZLIB if( format == VTK::FileFormat::zlib_compressed ) str << " compressor=\"vtkZLibDataCompressor\""; #endif str << ">\n"; str << "<PUnstructuredGrid GhostLevel=\"" << GhostLevel << "\""; if( MinCommonVertices > 0 ) str << " MinCommonVertices=\"" << MinCommonVertices << "\""; str << ">\n"; vtkfileOpen = true; } template< typename Mesh > void PVTUWriter< Mesh >::writePoints( const Mesh& mesh ) { str << "<PPoints>\n"; writePDataArray< typename Mesh::RealType >( "Points", 3 ); str << "</PPoints>\n"; } template< typename Mesh > void PVTUWriter< Mesh >::writeFooter() { closePCellData(); closePPointData(); str << "</PUnstructuredGrid>\n"; str << "</VTKFile>\n"; } template< typename Mesh > PVTUWriter< Mesh >::~PVTUWriter() { if( vtkfileOpen ) writeFooter(); } template< typename Mesh > void PVTUWriter< Mesh >::openPCellData() { if( pCellDataClosed ) throw std::logic_error("The <PCellData> tag has already been closed."); closePPointData(); if( ! pCellDataOpen ) { str << "<PCellData>\n"; pCellDataOpen = true; } } template< typename Mesh > void PVTUWriter< Mesh >::closePCellData() { if( pCellDataOpen ) { str << "</PCellData>\n"; pCellDataClosed = true; pCellDataOpen = false; } } template< typename Mesh > void PVTUWriter< Mesh >::openPPointData() { if( pPointDataClosed ) throw std::logic_error("The <PPointData> tag has already been closed."); closePCellData(); if( ! pPointDataOpen ) { str << "<PPointData>\n"; pPointDataOpen = true; } } template< typename Mesh > void PVTUWriter< Mesh >::closePPointData() { if( pPointDataOpen ) { str << "</PPointData>\n"; pPointDataClosed = true; pPointDataOpen = false; } } } // namespace Writers } // namespace Meshes } // namespace TNL src/Tools/tnl-decompose-mesh.cpp +18 −54 Original line number Diff line number Diff line Loading @@ -10,10 +10,10 @@ // Implemented by: Jakub Klinkovský #include <TNL/FileName.h> #include <TNL/Config/parseCommandLine.h> #include <TNL/Meshes/TypeResolver/TypeResolver.h> #include <TNL/Meshes/Writers/VTUWriter.h> #include <TNL/Meshes/Writers/PVTUWriter.h> #include <metis.h> Loading Loading @@ -549,15 +549,24 @@ struct DecomposeMesh for( unsigned p = 1; p < nparts; p++ ) points_offsets[p] = points_offsets[p-1] + points_counts[p-1]; // prepare output file name const String outputFile = parameters.template getParameter< String >( "output-file" ); FileName outputFileName( removeFileNameExtension( outputFile ) + ".subdomain", "vtu" ); outputFileName.setDigitsCount( std::floor(std::log10( nparts - 1 )) + 1 ); // write a .pvtu file using PVTU = Meshes::Writers::PVTUWriter< Mesh >; const std::string pvtuFileName = parameters.template getParameter< String >( "output-file" ); std::ofstream file( pvtuFileName ); PVTU pvtu( file ); pvtu.template writeEntities< Mesh::getMeshDimension() >( Mesh{}, ghost_levels, ncommon ); if( ghost_levels > 0 ) { // the PointData and CellData from the individual files should be added here pvtu.template writePPointData< std::uint8_t >( Meshes::VTK::ghostArrayName() ); pvtu.template writePPointData< Index >( "GlobalIndex" ); pvtu.template writePCellData< std::uint8_t >( Meshes::VTK::ghostArrayName() ); pvtu.template writePCellData< Index >( "GlobalIndex" ); } std::cout << "Writing subdomains..." << std::endl; for( unsigned p = 0; p < nparts; p++ ) { outputFileName.setIndex( p ); std::cout << outputFileName.getFileName() << std::endl; const std::string outputFileName = pvtu.addPiece( pvtuFileName, p ); std::cout << outputFileName << std::endl; // Due to ghost levels, we don't know the number of cells, let alone points, in each // subdomain ahead of time. Hence, we use dynamic data structures instead of MeshBuilder. Loading Loading @@ -673,7 +682,7 @@ struct DecomposeMesh // write the subdomain using Writer = Meshes::Writers::VTUWriter< Mesh >; std::ofstream file( outputFileName.getFileName() ); std::ofstream file( outputFileName ); Writer writer( file ); writer.template writeEntities< Mesh::getMeshDimension() >( subdomain ); if( ghost_levels > 0 ) { Loading @@ -684,51 +693,6 @@ struct DecomposeMesh } } // write a .pvtu file std::ofstream file( outputFile.getString() ); // TODO: refactor into a PVTU writer using HeaderType = std::uint64_t; using namespace Meshes; file << "<?xml version=\"1.0\"?>\n"; file << "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\""; if( isLittleEndian() ) file << " byte_order=\"LittleEndian\""; else file << " byte_order=\"BigEndian\""; file << " header_type=\"" << VTK::getTypeName( HeaderType{} ) << "\""; #ifdef HAVE_ZLIB // if( format == VTK::FileFormat::zlib_compressed ) file << " compressor=\"vtkZLibDataCompressor\""; #endif file << ">\n"; file << "<PUnstructuredGrid GhostLevel=\"" << ghost_levels << "\" MinCommonVertices=\"" << ncommon << "\">\n"; file << "<PPoints>\n"; file << "<PDataArray type=\"" << VTK::getTypeName( typename Mesh::RealType{} ) << "\" Name=\"Points\" NumberOfComponents=\"3\"/>\n"; file << "</PPoints>\n"; if( ghost_levels > 0 ) { // the PointData and CellData from the individual files should be added here file << "<PPointData>\n"; file << "<PDataArray type=\"" << VTK::getTypeName( std::uint8_t{} ) << "\" Name=\"" << Meshes::VTK::ghostArrayName() << "\" NumberOfComponents=\"1\"/>\n"; file << "<PDataArray type=\"" << VTK::getTypeName( Index{} ) << "\" Name=\"GlobalIndex\" NumberOfComponents=\"1\"/>\n"; file << "</PPointData>\n"; file << "<PCellData>\n"; file << "<PDataArray type=\"" << VTK::getTypeName( std::uint8_t{} ) << "\" Name=\"" << Meshes::VTK::ghostArrayName() << "\" NumberOfComponents=\"1\"/>\n"; file << "<PDataArray type=\"" << VTK::getTypeName( Index{} ) << "\" Name=\"GlobalIndex\" NumberOfComponents=\"1\"/>\n"; file << "</PCellData>\n"; } for( unsigned p = 0; p < nparts; p++ ) { outputFileName.setIndex( p ); // make sure the source path is relative to the main .pvtu file // TODO: use proper path library const auto parts = outputFileName.getFileName().split('/'); const std::string basename = parts.back(); file << "<Piece Source=\"" << basename << "\"/>\n"; } file << "</PUnstructuredGrid>\n"; file << "</VTKFile>\n"; return true; } }; Loading @@ -745,7 +709,7 @@ int main( int argc, char* argv[] ) const String inputFileName = parameters.getParameter< String >( "input-file" ); const String outputFile = parameters.template getParameter< String >( "output-file" ); if( getFileExtension( outputFile ) != "pvtu" ) { if( ! outputFile.endsWith( ".pvtu" ) ) { std::cerr << "Error: the output file must have a '.pvtu' extension." << std::endl; return EXIT_FAILURE; } Loading Loading
CMakeLists.txt +4 −0 Original line number Diff line number Diff line Loading @@ -160,6 +160,10 @@ if( DEFINED ENV{CI_JOB_NAME} OR ${CMAKE_GENERATOR} STREQUAL "Ninja" ) endif() endif() # add the filesystem library to all targets # https://en.cppreference.com/w/cpp/filesystem link_libraries( stdc++fs ) # gtest has to be built before we add the MPI flags if( ${WITH_TESTS} OR ${WITH_MATRIX_TESTS} ) enable_testing() Loading
src/TNL/Meshes/Writers/PVTUWriter.h 0 → 100644 +107 −0 Original line number Diff line number Diff line /*************************************************************************** PVTUWriter.h - description ------------------- begin : Apr 17, 2020 copyright : (C) 2020 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ // Implemented by: Jakub Klinkovský #pragma once #include <TNL/Meshes/Writers/VTUWriter.h> #include <TNL/Meshes/DistributedMeshes/DistributedMesh.h> namespace TNL { namespace Meshes { namespace Writers { // NOTE: Mesh should be the local mesh type, not DistributedMesh template< typename Mesh > class PVTUWriter { using HeaderType = std::uint64_t; public: using MeshRealType = typename Mesh::RealType; using IndexType = typename Mesh::GlobalIndexType; PVTUWriter() = delete; PVTUWriter( std::ostream& str, VTK::FileFormat format = VTK::FileFormat::zlib_compressed ) : str(str), format(format) {} // If desired, cycle and time of the simulation can put into the file. This follows the instructions at // http://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files void writeMetadata( std::int32_t cycle = -1, double time = -1 ); template< int EntityDimension = Mesh::getMeshDimension() > void writeEntities( const DistributedMeshes::DistributedMesh< Mesh >& distributedMesh ); template< int EntityDimension = Mesh::getMeshDimension() > void writeEntities( const Mesh& mesh, const unsigned GhostLevel = 0, const unsigned MinCommonVertices = 0 ); template< typename ValueType > void writePPointData( const String& name, const int numberOfComponents = 1 ); template< typename ValueType > void writePCellData( const String& name, const int numberOfComponents = 1 ); template< typename ValueType > void writePDataArray( const String& name, const int numberOfComponents = 1 ); // add a single piece and return its source path // (useful for sequential writing, e.g. from tnl-decompose-mesh) std::string addPiece( const String& mainFileName, const unsigned subdomainIndex ); // add all pieces and return the source path for the current rank // (useful for parallel writing) template< typename Communicator > std::string addPiece( const String& mainFileName, const typename Communicator::CommunicationGroup group ); ~PVTUWriter(); protected: void writeHeader( const unsigned GhostLevel = 0, const unsigned MinCommonVertices = 0 ); void writePoints( const Mesh& mesh ); void writeFooter(); std::ostream& str; VTK::FileFormat format; // indicator if the <VTKFile> tag is open bool vtkfileOpen = false; // indicators if a <PCellData> tag is open or closed bool pCellDataOpen = false; bool pCellDataClosed = false; // indicators if a <PPointData> tag is open or closed bool pPointDataOpen = false; bool pPointDataClosed = false; void openPCellData(); void closePCellData(); void openPPointData(); void closePPointData(); }; } // namespace Writers } // namespace Meshes } // namespace TNL #include <TNL/Meshes/Writers/PVTUWriter.hpp>
src/TNL/Meshes/Writers/PVTUWriter.hpp 0 → 100644 +255 −0 Original line number Diff line number Diff line /*************************************************************************** PVTUWriter.hpp - description ------------------- begin : Apr 17, 2020 copyright : (C) 2020 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ // Implemented by: Jakub Klinkovský #pragma once #include <experimental/filesystem> #include <TNL/Meshes/Writers/PVTUWriter.h> namespace TNL { namespace Meshes { namespace Writers { template< typename Mesh > void PVTUWriter< Mesh >::writeMetadata( int cycle, double time ) { if( ! vtkfileOpen ) throw std::logic_error("writeMetadata has to be called after writeEntities in case of the PVTU format, otherwise header attributes would be left unset." ); if( cycle >= 0 || time >= 0 ) str << "<FieldData>\n"; if( cycle >= 0 ) { str << "<DataArray type=\"Int32\" Name=\"CYCLE\" NumberOfTuples=\"1\" format=\"ascii\">" << cycle << "</DataArray>\n"; } if( time >= 0 ) { str.precision( std::numeric_limits< double >::digits10 ); str << "<DataArray type=\"Float64\" Name=\"TIME\" NumberOfTuples=\"1\" format=\"ascii\">" << time << "</DataArray>\n"; } if( cycle >= 0 || time >= 0 ) str << "</FieldData>\n"; } template< typename Mesh > template< int EntityDimension > void PVTUWriter< Mesh >::writeEntities( const DistributedMeshes::DistributedMesh< Mesh >& distributedMesh ) { writeEntities< EntityDimension >( distributedMesh.getLocalMesh(), distributedMesh.getGhostLevels(), Mesh::Config::dualGraphMinCommonVertices ); } template< typename Mesh > template< int EntityDimension > void PVTUWriter< Mesh >::writeEntities( const Mesh& mesh, const unsigned GhostLevel, const unsigned MinCommonVertices ) { if( ! vtkfileOpen ) writeHeader( GhostLevel, MinCommonVertices ); // write points writePoints( mesh ); } template< typename Mesh > template< typename ValueType > void PVTUWriter< Mesh >::writePPointData( const String& name, const int numberOfComponents ) { if( ! vtkfileOpen ) throw std::logic_error("The VTKFile has not been opened yet - call writeEntities first."); openPPointData(); writePDataArray< ValueType >( name, numberOfComponents ); } template< typename Mesh > template< typename ValueType > void PVTUWriter< Mesh >::writePCellData( const String& name, const int numberOfComponents ) { if( ! vtkfileOpen ) throw std::logic_error("The VTKFile has not been opened yet - call writeEntities first."); openPCellData(); writePDataArray< ValueType >( name, numberOfComponents ); } template< typename Mesh > template< typename ValueType > void PVTUWriter< Mesh >::writePDataArray( const String& name, const int numberOfComponents ) { if( numberOfComponents != 0 && numberOfComponents != 1 && numberOfComponents != 3 ) throw std::logic_error("Unsupported numberOfComponents parameter: " + std::to_string(numberOfComponents)); str << "<PDataArray type=\"" << VTK::getTypeName( ValueType{} ) << "\" "; str << "Name=\"" << name << "\" "; str << "NumberOfComponents=\"" << numberOfComponents << "\"/>\n"; } template< typename Mesh > std::string PVTUWriter< Mesh >::addPiece( const String& mainFileName, const unsigned subdomainIndex ) { if( ! mainFileName.endsWith( ".pvtu" ) ) throw std::logic_error("The mainFileName parameter must be the name of the " ".pvtu file (i.e., it must have the .pvtu suffix)."); // close PCellData and PPointData sections closePCellData(); closePPointData(); namespace fs = std::experimental::filesystem; // get the basename of the main file (filename without extension) const fs::path mainPath = mainFileName.getString(); const fs::path basename = mainPath.stem(); // create subdirectory for subdomains const fs::path subdirectory = mainPath.parent_path() / basename; fs::create_directory( subdirectory ); // write <Piece> tag const std::string subfile = "subdomain." + std::to_string(subdomainIndex) + ".vtu"; const std::string source = basename / subfile; str << "<Piece Source=\"" << source << "\"/>\n"; // return subfile path return subdirectory / subfile; } template< typename Mesh > template< typename Communicator > std::string PVTUWriter< Mesh >::addPiece( const String& mainFileName, const typename Communicator::CommunicationGroup group ) { std::string source; for( int i = 0; i < Communicator::GetSize( group ); i++ ) { const std::string s = addPiece( mainFileName, i ); if( i == Communicator::GetRank( group ) ) source = s; } return source; } template< typename Mesh > void PVTUWriter< Mesh >::writeHeader( const unsigned GhostLevel, const unsigned MinCommonVertices ) { str << "<?xml version=\"1.0\"?>\n"; str << "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\""; if( isLittleEndian() ) str << " byte_order=\"LittleEndian\""; else str << " byte_order=\"BigEndian\""; str << " header_type=\"" << VTK::getTypeName( HeaderType{} ) << "\""; #ifdef HAVE_ZLIB if( format == VTK::FileFormat::zlib_compressed ) str << " compressor=\"vtkZLibDataCompressor\""; #endif str << ">\n"; str << "<PUnstructuredGrid GhostLevel=\"" << GhostLevel << "\""; if( MinCommonVertices > 0 ) str << " MinCommonVertices=\"" << MinCommonVertices << "\""; str << ">\n"; vtkfileOpen = true; } template< typename Mesh > void PVTUWriter< Mesh >::writePoints( const Mesh& mesh ) { str << "<PPoints>\n"; writePDataArray< typename Mesh::RealType >( "Points", 3 ); str << "</PPoints>\n"; } template< typename Mesh > void PVTUWriter< Mesh >::writeFooter() { closePCellData(); closePPointData(); str << "</PUnstructuredGrid>\n"; str << "</VTKFile>\n"; } template< typename Mesh > PVTUWriter< Mesh >::~PVTUWriter() { if( vtkfileOpen ) writeFooter(); } template< typename Mesh > void PVTUWriter< Mesh >::openPCellData() { if( pCellDataClosed ) throw std::logic_error("The <PCellData> tag has already been closed."); closePPointData(); if( ! pCellDataOpen ) { str << "<PCellData>\n"; pCellDataOpen = true; } } template< typename Mesh > void PVTUWriter< Mesh >::closePCellData() { if( pCellDataOpen ) { str << "</PCellData>\n"; pCellDataClosed = true; pCellDataOpen = false; } } template< typename Mesh > void PVTUWriter< Mesh >::openPPointData() { if( pPointDataClosed ) throw std::logic_error("The <PPointData> tag has already been closed."); closePCellData(); if( ! pPointDataOpen ) { str << "<PPointData>\n"; pPointDataOpen = true; } } template< typename Mesh > void PVTUWriter< Mesh >::closePPointData() { if( pPointDataOpen ) { str << "</PPointData>\n"; pPointDataClosed = true; pPointDataOpen = false; } } } // namespace Writers } // namespace Meshes } // namespace TNL
src/Tools/tnl-decompose-mesh.cpp +18 −54 Original line number Diff line number Diff line Loading @@ -10,10 +10,10 @@ // Implemented by: Jakub Klinkovský #include <TNL/FileName.h> #include <TNL/Config/parseCommandLine.h> #include <TNL/Meshes/TypeResolver/TypeResolver.h> #include <TNL/Meshes/Writers/VTUWriter.h> #include <TNL/Meshes/Writers/PVTUWriter.h> #include <metis.h> Loading Loading @@ -549,15 +549,24 @@ struct DecomposeMesh for( unsigned p = 1; p < nparts; p++ ) points_offsets[p] = points_offsets[p-1] + points_counts[p-1]; // prepare output file name const String outputFile = parameters.template getParameter< String >( "output-file" ); FileName outputFileName( removeFileNameExtension( outputFile ) + ".subdomain", "vtu" ); outputFileName.setDigitsCount( std::floor(std::log10( nparts - 1 )) + 1 ); // write a .pvtu file using PVTU = Meshes::Writers::PVTUWriter< Mesh >; const std::string pvtuFileName = parameters.template getParameter< String >( "output-file" ); std::ofstream file( pvtuFileName ); PVTU pvtu( file ); pvtu.template writeEntities< Mesh::getMeshDimension() >( Mesh{}, ghost_levels, ncommon ); if( ghost_levels > 0 ) { // the PointData and CellData from the individual files should be added here pvtu.template writePPointData< std::uint8_t >( Meshes::VTK::ghostArrayName() ); pvtu.template writePPointData< Index >( "GlobalIndex" ); pvtu.template writePCellData< std::uint8_t >( Meshes::VTK::ghostArrayName() ); pvtu.template writePCellData< Index >( "GlobalIndex" ); } std::cout << "Writing subdomains..." << std::endl; for( unsigned p = 0; p < nparts; p++ ) { outputFileName.setIndex( p ); std::cout << outputFileName.getFileName() << std::endl; const std::string outputFileName = pvtu.addPiece( pvtuFileName, p ); std::cout << outputFileName << std::endl; // Due to ghost levels, we don't know the number of cells, let alone points, in each // subdomain ahead of time. Hence, we use dynamic data structures instead of MeshBuilder. Loading Loading @@ -673,7 +682,7 @@ struct DecomposeMesh // write the subdomain using Writer = Meshes::Writers::VTUWriter< Mesh >; std::ofstream file( outputFileName.getFileName() ); std::ofstream file( outputFileName ); Writer writer( file ); writer.template writeEntities< Mesh::getMeshDimension() >( subdomain ); if( ghost_levels > 0 ) { Loading @@ -684,51 +693,6 @@ struct DecomposeMesh } } // write a .pvtu file std::ofstream file( outputFile.getString() ); // TODO: refactor into a PVTU writer using HeaderType = std::uint64_t; using namespace Meshes; file << "<?xml version=\"1.0\"?>\n"; file << "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\""; if( isLittleEndian() ) file << " byte_order=\"LittleEndian\""; else file << " byte_order=\"BigEndian\""; file << " header_type=\"" << VTK::getTypeName( HeaderType{} ) << "\""; #ifdef HAVE_ZLIB // if( format == VTK::FileFormat::zlib_compressed ) file << " compressor=\"vtkZLibDataCompressor\""; #endif file << ">\n"; file << "<PUnstructuredGrid GhostLevel=\"" << ghost_levels << "\" MinCommonVertices=\"" << ncommon << "\">\n"; file << "<PPoints>\n"; file << "<PDataArray type=\"" << VTK::getTypeName( typename Mesh::RealType{} ) << "\" Name=\"Points\" NumberOfComponents=\"3\"/>\n"; file << "</PPoints>\n"; if( ghost_levels > 0 ) { // the PointData and CellData from the individual files should be added here file << "<PPointData>\n"; file << "<PDataArray type=\"" << VTK::getTypeName( std::uint8_t{} ) << "\" Name=\"" << Meshes::VTK::ghostArrayName() << "\" NumberOfComponents=\"1\"/>\n"; file << "<PDataArray type=\"" << VTK::getTypeName( Index{} ) << "\" Name=\"GlobalIndex\" NumberOfComponents=\"1\"/>\n"; file << "</PPointData>\n"; file << "<PCellData>\n"; file << "<PDataArray type=\"" << VTK::getTypeName( std::uint8_t{} ) << "\" Name=\"" << Meshes::VTK::ghostArrayName() << "\" NumberOfComponents=\"1\"/>\n"; file << "<PDataArray type=\"" << VTK::getTypeName( Index{} ) << "\" Name=\"GlobalIndex\" NumberOfComponents=\"1\"/>\n"; file << "</PCellData>\n"; } for( unsigned p = 0; p < nparts; p++ ) { outputFileName.setIndex( p ); // make sure the source path is relative to the main .pvtu file // TODO: use proper path library const auto parts = outputFileName.getFileName().split('/'); const std::string basename = parts.back(); file << "<Piece Source=\"" << basename << "\"/>\n"; } file << "</PUnstructuredGrid>\n"; file << "</VTKFile>\n"; return true; } }; Loading @@ -745,7 +709,7 @@ int main( int argc, char* argv[] ) const String inputFileName = parameters.getParameter< String >( "input-file" ); const String outputFile = parameters.template getParameter< String >( "output-file" ); if( getFileExtension( outputFile ) != "pvtu" ) { if( ! outputFile.endsWith( ".pvtu" ) ) { std::cerr << "Error: the output file must have a '.pvtu' extension." << std::endl; return EXIT_FAILURE; } Loading