Skip to content
Snippets Groups Projects
VTKWriter_impl.h 19 KiB
Newer Older
  • Learn to ignore specific revisions
  • /***************************************************************************
                              VTKWriter.h  -  description
                                 -------------------
        begin                : Mar 04, 2017
        copyright            : (C) 2017 by Tomas Oberhuber et al.
        email                : tomas.oberhuber@fjfi.cvut.cz
     ***************************************************************************/
    
    /* See Copyright Notice in tnl/Copyright */
    
    #pragma once
    
    
    #include <TNL/Meshes/Writers/VTKWriter.h>
    
    #include <TNL/Meshes/Readers/EntityShape.h>
    
    
    namespace TNL {
    namespace Meshes {
    namespace Writers {
    
    namespace __impl {
    
    
    template< typename T, typename R = void >
    struct enable_if_type
    
    template< typename T, typename Enable = void >
    struct has_entity_topology : std::false_type {};
    
    template< typename T >
    struct has_entity_topology< T, typename enable_if_type< typename T::EntityTopology >::type >
    : std::true_type
    {};
    
    template< typename Entity,
              bool _is_mesh_entity = has_entity_topology< Entity >::value >
    struct VerticesPerEntity
    
       static constexpr int count = Entity::getVerticesCount();
    
    template< typename MeshConfig, typename Device >
    struct VerticesPerEntity< MeshEntity< MeshConfig, Device, Topologies::Vertex >, true >
    
    };
    
    template< typename GridEntity >
    
    struct VerticesPerEntity< GridEntity, false >
    
    private:
       static constexpr int dim = GridEntity::getEntityDimension();
       static_assert( dim >= 0 && dim <= 3, "unexpected dimension of the grid entity" );
    
    public:
       static constexpr int count =
          (dim == 0) ? 1 :
          (dim == 1) ? 2 :
          (dim == 2) ? 4 :
                       8;
    
    template< typename GridEntity >
    struct GridEntityShape
    
    private:
       static constexpr int dim = GridEntity::getEntityDimension();
       static_assert( dim >= 0 && dim <= 3, "unexpected dimension of the grid entity" );
    
    public:
       static constexpr Readers::EntityShape shape =
          (dim == 0) ? Readers::EntityShape::Vertex :
          (dim == 1) ? Readers::EntityShape::Line :
          (dim == 2) ? Readers::EntityShape::Pixel :
                       Readers::EntityShape::Voxel;
    
    };
    
    
    template< typename Mesh >
    typename Mesh::GlobalIndexType
    getAllMeshEntitiesCount( const Mesh& mesh, DimensionTag< 0 > )
    {
       using EntityType = typename Mesh::template EntityType< 0 >;
       return mesh.template getEntitiesCount< EntityType >();
    }
    
    // TODO: specialization for disabled entities
    template< typename Mesh,
              typename DimensionTag = Meshes::DimensionTag< Mesh::getMeshDimension() > >
    typename Mesh::GlobalIndexType
    getAllMeshEntitiesCount( const Mesh& mesh, DimensionTag = DimensionTag() )
    {
       using EntityType = typename Mesh::template EntityType< DimensionTag::value >;
       return mesh.template getEntitiesCount< EntityType >() +
              getAllMeshEntitiesCount( mesh, typename DimensionTag::Decrement() );
    }
    
    
    template< typename Mesh >
    typename Mesh::GlobalIndexType
    getCellsListSize( const Mesh& mesh, DimensionTag< 0 > )
    {
       using EntityType = typename Mesh::template EntityType< 0 >;
       return mesh.template getEntitiesCount< EntityType >() * 2;
    }
    
    // TODO: specialization for disabled entities
    template< typename Mesh,
              typename DimensionTag = Meshes::DimensionTag< Mesh::getMeshDimension() > >
    typename Mesh::GlobalIndexType
    getCellsListSize( const Mesh& mesh, DimensionTag = DimensionTag() )
    {
       using EntityType = typename Mesh::template EntityType< DimensionTag::value >;
       const auto verticesPerEntity = VerticesPerEntity< EntityType >::count;
       return ( mesh.template getEntitiesCount< EntityType >() * ( verticesPerEntity + 1 ) ) +
              getCellsListSize( mesh, typename DimensionTag::Decrement() );
    }
    
    
    // TODO: specialization for disabled entities
    // Unstructured meshes, entities
    template< typename Mesh, int EntityDimension >
    struct MeshEntitiesVTKWriter
    {
       static void exec( const Mesh& mesh, std::ostream& str )
       {
          using EntityType = typename Mesh::template EntityType< EntityDimension >;
          using Index = typename Mesh::GlobalIndexType;
    
          const Index entitiesCount = mesh.template getEntitiesCount< EntityType >();
          const Index verticesPerEntity = VerticesPerEntity< EntityType >::count;;
          for( Index i = 0; i < entitiesCount; i++ ) {
             const auto& entity = mesh.template getEntity< EntityType >( i );
             str << verticesPerEntity;
             for( Index j = 0; j < verticesPerEntity; j++ )
                str << " " << entity.template getSubentityIndex< 0 >( j );
             str << "\n";
          }
       }
    };
    
    // Unstructured meshes, vertices
    template< typename Mesh >
    struct MeshEntitiesVTKWriter< Mesh, 0 >
    {
       static void exec( const Mesh& mesh, std::ostream& str )
       {
          using EntityType = typename Mesh::template EntityType< 0 >;
          using Index = typename Mesh::GlobalIndexType;
    
          const Index entitiesCount = mesh.template getEntitiesCount< EntityType >();
          const Index verticesPerEntity = 1;
          for( Index i = 0; i < entitiesCount; i++ ) {
             str << verticesPerEntity << " " << i << "\n";
          }
       }
    };
    
    // 1D grids, cells
    template< typename MeshReal,
              typename Device,
              typename MeshIndex >
    struct MeshEntitiesVTKWriter< Meshes::Grid< 1, MeshReal, Device, MeshIndex >, 1 >
    {
       using MeshType = Meshes::Grid< 1, MeshReal, Device, MeshIndex >;
    
       static void exec( const MeshType& mesh, std::ostream& str )
       {
          for( MeshIndex i = 0; i < mesh.getDimensions().x(); i++ )
             str << "2 " << i << " " << i+1 << "\n";
       }
    };
    
    // 1D grids, vertices
    template< typename MeshReal,
              typename Device,
              typename MeshIndex >
    struct MeshEntitiesVTKWriter< Meshes::Grid< 1, MeshReal, Device, MeshIndex >, 0 >
    {
       using MeshType = Meshes::Grid< 1, MeshReal, Device, MeshIndex >;
    
       static void exec( const MeshType& mesh, std::ostream& str )
       {
          for( MeshIndex i = 0; i < mesh.getDimensions().x() + 1; i++ )
             str << "1 " << i << "\n";
       }
    };
    
    // 2D grids, cells
    template< typename MeshReal,
              typename Device,
              typename MeshIndex >
    struct MeshEntitiesVTKWriter< Meshes::Grid< 2, MeshReal, Device, MeshIndex >, 2 >
    {
       using MeshType = Meshes::Grid< 2, MeshReal, Device, MeshIndex >;
    
       static void exec( const MeshType& mesh, std::ostream& str )
       {
          for( MeshIndex j = 0; j < mesh.getDimensions().y(); j++ )
             for( MeshIndex i = 0; i < mesh.getDimensions().x(); i++ )
                str << "4 " << j * ( mesh.getDimensions().x() + 1 ) + i << " "
                            << j * ( mesh.getDimensions().x() + 1 ) + i + 1 << " "
                            << (j+1) * ( mesh.getDimensions().x() + 1 ) + i << " "
                            << (j+1) * ( mesh.getDimensions().x() + 1 ) + i + 1 << "\n";
       }
    };
    
    // 2D grids, faces
    template< typename MeshReal,
              typename Device,
              typename MeshIndex >
    struct MeshEntitiesVTKWriter< Meshes::Grid< 2, MeshReal, Device, MeshIndex >, 1 >
    {
       using MeshType = Meshes::Grid< 2, MeshReal, Device, MeshIndex >;
    
       static void exec( const MeshType& mesh, std::ostream& str )
       {
          for( MeshIndex j = 0; j < mesh.getDimensions().y(); j++ )
             for( MeshIndex i = 0; i < ( mesh.getDimensions().x() + 1 ); i++ )
                str << "2 " << j * ( mesh.getDimensions().x() + 1 ) + i << " "
                            << (j+1) * ( mesh.getDimensions().x() + 1 ) + i << "\n";
    
          for( MeshIndex j = 0; j < (mesh.getDimensions().y()+1); j++ )
             for( MeshIndex i = 0; i < mesh.getDimensions().x(); i++ )
                str << "2 " << j * ( mesh.getDimensions().x() + 1 ) + i << " "
                            << j * ( mesh.getDimensions().x() + 1 ) + i + 1 << "\n";
       }
    };
    
    // 2D grids, vertices
    template< typename MeshReal,
              typename Device,
              typename MeshIndex >
    struct MeshEntitiesVTKWriter< Meshes::Grid< 2, MeshReal, Device, MeshIndex >, 0 >
    {
       using MeshType = Meshes::Grid< 2, MeshReal, Device, MeshIndex >;
    
       static void exec( const MeshType& mesh, std::ostream& str )
       {
          for( MeshIndex j = 0; j < ( mesh.getDimensions().y() + 1 ); j++ )
             for( MeshIndex i = 0; i < ( mesh.getDimensions().x() + 1 ); i++ )
                str << "1 " << j * mesh.getDimensions().x() + i << "\n";
       }
    };
    
    // 3D grids, cells
    template< typename MeshReal,
              typename Device,
              typename MeshIndex >
    struct MeshEntitiesVTKWriter< Meshes::Grid< 3, MeshReal, Device, MeshIndex >, 3 >
    {
       using MeshType = Meshes::Grid< 3, MeshReal, Device, MeshIndex >;
    
       static void exec( const MeshType& mesh, std::ostream& str )
       {
          for( MeshIndex k = 0; k < mesh.getDimensions().z(); k++ )
             for( MeshIndex j = 0; j < mesh.getDimensions().y(); j++ )
                for( MeshIndex i = 0; i < mesh.getDimensions().x(); i++ )
                   str << "8 " << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i + 1 << " "
                               << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + (j+1) * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + (j+1) * ( mesh.getDimensions().x() + 1 ) + i + 1 << " "
                               << (k+1) * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << (k+1) * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i + 1 << " "
                               << (k+1) * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + (j+1) * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << (k+1) * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + (j+1) * ( mesh.getDimensions().x() + 1 ) + i + 1 << "\n";
       }
    };
    
    // 3D grids, faces
    template< typename MeshReal,
              typename Device,
              typename MeshIndex >
    struct MeshEntitiesVTKWriter< Meshes::Grid< 3, MeshReal, Device, MeshIndex >, 2 >
    {
       using MeshType = Meshes::Grid< 3, MeshReal, Device, MeshIndex >;
    
       static void exec( const MeshType& mesh, std::ostream& str )
       {
          for( MeshIndex k = 0; k < mesh.getDimensions().z(); k++ )
             for( MeshIndex j = 0; j < mesh.getDimensions().y(); j++ )
                for( MeshIndex i = 0; i <= mesh.getDimensions().x(); i++ )
                   str << "4 " << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + (j+1) * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << (k+1) * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << (k+1) * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + (j+1) * ( mesh.getDimensions().x() + 1 ) + i << "\n";
    
          for( MeshIndex k = 0; k < mesh.getDimensions().z(); k++ )
             for( MeshIndex j = 0; j <= mesh.getDimensions().y(); j++ )
                for( MeshIndex i = 0; i < mesh.getDimensions().x(); i++ )
                   str << "4 " << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i + 1 << " "
                               << (k+1) * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << (k+1) * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i + 1 << "\n";
    
          for( MeshIndex k = 0; k <= mesh.getDimensions().z(); k++ )
             for( MeshIndex j = 0; j < mesh.getDimensions().y(); j++ )
                for( MeshIndex i = 0; i < mesh.getDimensions().x(); i++ )
                   str << "4 " << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i + 1 << " "
                               << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + (j+1) * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + (j+1) * ( mesh.getDimensions().x() + 1 ) + i + 1 << "\n";
       }
    };
    
    // 3D grids, edges
    template< typename MeshReal,
              typename Device,
              typename MeshIndex >
    struct MeshEntitiesVTKWriter< Meshes::Grid< 3, MeshReal, Device, MeshIndex >, 1 >
    {
       using MeshType = Meshes::Grid< 3, MeshReal, Device, MeshIndex >;
    
       static void exec( const MeshType& mesh, std::ostream& str )
       {
          for( MeshIndex k = 0; k <= mesh.getDimensions().z(); k++ )
             for( MeshIndex j = 0; j <= mesh.getDimensions().y(); j++ )
                for( MeshIndex i = 0; i < mesh.getDimensions().x(); i++ )
                   str << "2 " << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i + 1 << "\n";
    
          for( MeshIndex k = 0; k <= mesh.getDimensions().z(); k++ )
             for( MeshIndex j = 0; j < mesh.getDimensions().y(); j++ )
                for( MeshIndex i = 0; i <= mesh.getDimensions().x(); i++ )
                   str << "2 " << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + (j+1) * ( mesh.getDimensions().x() + 1 ) + i << "\n";
    
          for( MeshIndex k = 0; k < mesh.getDimensions().z(); k++ )
             for( MeshIndex j = 0; j <= mesh.getDimensions().y(); j++ )
                for( MeshIndex i = 0; i <= mesh.getDimensions().x(); i++ )
                   str << "2 " << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << " "
                               << (k+1) * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i << "\n";
       }
    };
    
    // 3D grids, vertices
    template< typename MeshReal,
              typename Device,
              typename MeshIndex >
    struct MeshEntitiesVTKWriter< Meshes::Grid< 3, MeshReal, Device, MeshIndex >, 0 >
    {
       using MeshType = Meshes::Grid< 3, MeshReal, Device, MeshIndex >;
    
       static void exec( const MeshType& mesh, std::ostream& str )
       {
          for( MeshIndex k = 0; k < ( mesh.getDimensions().z() + 1 ); k++ )
             for( MeshIndex j = 0; j < ( mesh.getDimensions().y() + 1 ); j++ )
                for( MeshIndex i = 0; i < ( mesh.getDimensions().x() + 1 ); i++ )
                   str << "1 " << k * ( mesh.getDimensions().y() + 1 ) * ( mesh.getDimensions().x() + 1 ) + j * ( mesh.getDimensions().x() + 1 ) + i  << "\n";
       }
    };
    
    
    // TODO: specialization for disabled entities
    template< typename Mesh, int EntityDimension >
    struct MeshEntityTypesVTKWriter
    {
       static void exec( const Mesh& mesh, std::ostream& str )
       {
          using EntityType = typename Mesh::template EntityType< EntityDimension >;
          using Index = typename Mesh::GlobalIndexType;
    
          const Index entitiesCount = mesh.template getEntitiesCount< EntityType >();
          for( Index i = 0; i < entitiesCount; i++ ) {
    
             const int type = (int) Meshes::Readers::TopologyToEntityShape< typename EntityType::EntityTopology >::shape;
    
             str << type << "\n";
          }
       }
    };
    
    template< int Dimension,
              typename MeshReal,
              typename Device,
              typename MeshIndex,
              int EntityDimension >
    struct MeshEntityTypesVTKWriter< Grid< Dimension, MeshReal, Device, MeshIndex >, EntityDimension >
    {
       using MeshType = Grid< Dimension, MeshReal, Device, MeshIndex >;
    
       static void exec( const MeshType& mesh, std::ostream& str )
       {
          using EntityType = typename MeshType::template EntityType< EntityDimension >;
    
          const MeshIndex entitiesCount = mesh.template getEntitiesCount< EntityType >();
          for( MeshIndex i = 0; i < entitiesCount; i++ ) {
    
             const int type = (int) __impl::GridEntityShape< EntityType >::shape;
    
             str << type << "\n";
          }
       }
    };
    
    } // namespace __impl
    
    template< typename Mesh >
    void
    VTKWriter< Mesh >::writeAllEntities( const Mesh& mesh, std::ostream& str )
    {
       writeHeader( mesh, str );
       writePoints( mesh, str );
    
       const Index allEntitiesCount = __impl::getAllMeshEntitiesCount( mesh );
       const Index cellsListSize = __impl::getCellsListSize( mesh );
    
       str << std::endl << "CELLS " << allEntitiesCount << " " << cellsListSize << std::endl;
       StaticFor< int, 0, Mesh::getMeshDimension() + 1, EntitiesWriter >::exec( mesh, str );
    
       str << std::endl << "CELL_TYPES " << allEntitiesCount << std::endl;
       StaticFor< int, 0, Mesh::getMeshDimension() + 1, EntityTypesWriter >::exec( mesh, str );
    }
    
    template< typename Mesh >
       template< int EntityDimension >
    void
    VTKWriter< Mesh >::writeEntities( const Mesh& mesh, std::ostream& str )
    {
       writeHeader( mesh, str );
       writePoints( mesh, str );
    
       using EntityType = typename Mesh::template EntityType< EntityDimension >;
       const Index entitiesCount = mesh.template getEntitiesCount< EntityType >();
       const Index verticesPerEntity = __impl::VerticesPerEntity< EntityType >::count;
       const Index cellsListSize = entitiesCount * ( verticesPerEntity + 1 );
    
       str << std::endl << "CELLS " << entitiesCount << " " << cellsListSize << std::endl;
       EntitiesWriter< EntityDimension >::exec( mesh, str );
    
       str << std::endl << "CELL_TYPES " << entitiesCount << std::endl;
       EntityTypesWriter< EntityDimension >::exec( mesh, str );
    }
    
    template< typename Mesh >
    void
    VTKWriter< Mesh >::writeHeader( const Mesh& mesh, std::ostream& str )
    {
        str << "# vtk DataFile Version 2.0\n"
            << "TNL DATA\n"
            << "ASCII\n"
            << "DATASET UNSTRUCTURED_GRID\n";
    }
    
    template< typename Mesh >
    void
    VTKWriter< Mesh >::writePoints( const Mesh& mesh, std::ostream& str )
    {
       const Index verticesCount = mesh.template getEntitiesCount< typename Mesh::Vertex >();
    
       str << "POINTS " << verticesCount << " " << getType< typename Mesh::RealType >() << std::endl;
       str.precision( std::numeric_limits< typename Mesh::RealType >::digits10 );
    
       for( Index i = 0; i < verticesCount; i++ ) {
          const auto& vertex = mesh.template getEntity< typename Mesh::Vertex >( i );
          const auto& point = vertex.getPoint();
          for( Index j = 0; j < point.size; j++ ) {
             str << point[ j ];
             if( j < point.size - 1 )
                str << " ";
          }
          // VTK needs zeros for unused dimensions
          for( Index j = 0; j < 3 - point.size; j++ )
             str << " 0";
          str << "\n";
       }
    }
    
    } // namespace Writers
    } // namespace Meshes
    } // namespace TNL