From 11ba9c9f1f009b0c2ec3deb5e3911a9324bd4e0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= <klinkovsky@mmg.fjfi.cvut.cz>
Date: Fri, 18 Oct 2019 15:07:08 +0200
Subject: [PATCH] Added MeshTraverserTest

---
 src/UnitTests/Meshes/CMakeLists.txt        |   9 +
 src/UnitTests/Meshes/MeshTraverserTest.cpp |   1 +
 src/UnitTests/Meshes/MeshTraverserTest.cu  |   1 +
 src/UnitTests/Meshes/MeshTraverserTest.h   | 434 +++++++++++++++++++++
 4 files changed, 445 insertions(+)
 create mode 100644 src/UnitTests/Meshes/MeshTraverserTest.cpp
 create mode 100644 src/UnitTests/Meshes/MeshTraverserTest.cu
 create mode 100644 src/UnitTests/Meshes/MeshTraverserTest.h

diff --git a/src/UnitTests/Meshes/CMakeLists.txt b/src/UnitTests/Meshes/CMakeLists.txt
index c71bde352d..91bf37215b 100644
--- a/src/UnitTests/Meshes/CMakeLists.txt
+++ b/src/UnitTests/Meshes/CMakeLists.txt
@@ -10,6 +10,10 @@ if( ${BUILD_CUDA} AND ${CUDA_VERSION_MAJOR} GREATER_EQUAL 9 )
                         OPTIONS ${CXX_TESTS_FLAGS} )
    TARGET_LINK_LIBRARIES( MeshTest ${GTEST_BOTH_LIBRARIES} )
 
+   CUDA_ADD_EXECUTABLE( MeshTraverserTest MeshTraverserTest.cu
+                        OPTIONS ${CXX_TESTS_FLAGS} )
+   TARGET_LINK_LIBRARIES( MeshTraverserTest ${GTEST_BOTH_LIBRARIES} )
+
    CUDA_ADD_EXECUTABLE( MeshOrderingTest MeshOrderingTest.cu
                         OPTIONS ${CXX_TESTS_FLAGS} )
    TARGET_LINK_LIBRARIES( MeshOrderingTest ${GTEST_BOTH_LIBRARIES} )
@@ -18,6 +22,10 @@ else()
    TARGET_COMPILE_OPTIONS( MeshTest PRIVATE ${CXX_TESTS_FLAGS} )
    TARGET_LINK_LIBRARIES( MeshTest ${GTEST_BOTH_LIBRARIES} )
 
+   ADD_EXECUTABLE( MeshTraverserTest MeshTraverserTest.cpp )
+   TARGET_COMPILE_OPTIONS( MeshTraverserTest PRIVATE ${CXX_TESTS_FLAGS} )
+   TARGET_LINK_LIBRARIES( MeshTraverserTest ${GTEST_BOTH_LIBRARIES} )
+
    ADD_EXECUTABLE( MeshOrderingTest MeshOrderingTest.cpp )
    TARGET_COMPILE_OPTIONS( MeshOrderingTest PRIVATE ${CXX_TESTS_FLAGS} )
    TARGET_LINK_LIBRARIES( MeshOrderingTest ${GTEST_BOTH_LIBRARIES} )
@@ -30,6 +38,7 @@ TARGET_LINK_LIBRARIES( MeshEntityTest ${GTEST_BOTH_LIBRARIES} )
 
 ADD_TEST( BoundaryTagsTest ${EXECUTABLE_OUTPUT_PATH}/BoundaryTagsTest${CMAKE_EXECUTABLE_SUFFIX} )
 ADD_TEST( MeshTest ${EXECUTABLE_OUTPUT_PATH}/MeshTest${CMAKE_EXECUTABLE_SUFFIX} )
+ADD_TEST( MeshTraverserTest ${EXECUTABLE_OUTPUT_PATH}/MeshTraverserTest${CMAKE_EXECUTABLE_SUFFIX} )
 ADD_TEST( MeshOrderingTest ${EXECUTABLE_OUTPUT_PATH}/MeshOrderingTest${CMAKE_EXECUTABLE_SUFFIX} )
 ADD_TEST( MeshEntityTest ${EXECUTABLE_OUTPUT_PATH}/MeshEntityTest${CMAKE_EXECUTABLE_SUFFIX} )
 
diff --git a/src/UnitTests/Meshes/MeshTraverserTest.cpp b/src/UnitTests/Meshes/MeshTraverserTest.cpp
new file mode 100644
index 0000000000..426d5fef5d
--- /dev/null
+++ b/src/UnitTests/Meshes/MeshTraverserTest.cpp
@@ -0,0 +1 @@
+#include "MeshTraverserTest.h"
diff --git a/src/UnitTests/Meshes/MeshTraverserTest.cu b/src/UnitTests/Meshes/MeshTraverserTest.cu
new file mode 100644
index 0000000000..426d5fef5d
--- /dev/null
+++ b/src/UnitTests/Meshes/MeshTraverserTest.cu
@@ -0,0 +1 @@
+#include "MeshTraverserTest.h"
diff --git a/src/UnitTests/Meshes/MeshTraverserTest.h b/src/UnitTests/Meshes/MeshTraverserTest.h
new file mode 100644
index 0000000000..b6c8208ad9
--- /dev/null
+++ b/src/UnitTests/Meshes/MeshTraverserTest.h
@@ -0,0 +1,434 @@
+#pragma once
+
+#ifdef HAVE_GTEST
+#include <gtest/gtest.h>
+
+#include <TNL/Meshes/Mesh.h>
+#include <TNL/Meshes/MeshEntity.h>
+#include <TNL/Meshes/DefaultConfig.h>
+#include <TNL/Meshes/Topologies/Quadrilateral.h>
+#include <TNL/Meshes/Topologies/Hexahedron.h>
+#include <TNL/Meshes/MeshBuilder.h>
+#include <TNL/Meshes/Traverser.h>
+
+namespace MeshTest {
+
+using namespace TNL;
+using namespace TNL::Meshes;
+
+using RealType = double;
+using Device = Devices::Host;
+using IndexType = int;
+
+static const char* TEST_FILE_NAME = "test_MeshTest.tnl";
+
+// FIXME: Traverser does not work with Id = void
+//class TestQuadrilateralMeshConfig : public DefaultConfig< Topologies::Quadrilateral >
+class TestQuadrilateralMeshConfig : public DefaultConfig< Topologies::Quadrilateral, 2, double, int, int, int >
+{
+public:
+   static constexpr bool entityStorage( int dimensions ) { return true; }
+   template< typename EntityTopology > static constexpr bool subentityStorage( EntityTopology, int SubentityDimensions ) { return true; }
+   template< typename EntityTopology > static constexpr bool subentityOrientationStorage( EntityTopology, int SubentityDimensions ) { return ( SubentityDimensions % 2 != 0 ); }
+   template< typename EntityTopology > static constexpr bool superentityStorage( EntityTopology, int SuperentityDimensions ) { return true; }
+};
+
+// FIXME: Traverser does not work with Id = void
+//class TestHexahedronMeshConfig : public DefaultConfig< Topologies::Hexahedron >
+class TestHexahedronMeshConfig : public DefaultConfig< Topologies::Hexahedron, 3, double, int, int, int >
+{
+public:
+   static constexpr bool entityStorage( int dimensions ) { return true; }
+   template< typename EntityTopology > static constexpr bool subentityStorage( EntityTopology, int SubentityDimensions ) { return true; }
+   template< typename EntityTopology > static constexpr bool subentityOrientationStorage( EntityTopology, int SubentityDimensions ) {  return ( SubentityDimensions % 2 != 0 ); }
+   template< typename EntityTopology > static constexpr bool superentityStorage( EntityTopology, int SuperentityDimensions ) { return true; }
+};
+
+struct TestEntitiesProcessor
+{
+   template< typename Mesh, typename UserData, typename Entity >
+   __cuda_callable__
+   static void processEntity( const Mesh& mesh, UserData& userData, const Entity& entity )
+   {
+      userData[ entity.getIndex() ] += 1;
+   }
+};
+
+template< typename EntityType, typename DeviceMeshPointer, typename HostArray >
+void testCudaTraverser( const DeviceMeshPointer& deviceMeshPointer,
+                        const HostArray& host_array_boundary,
+                        const HostArray& host_array_interior,
+                        const HostArray& host_array_all )
+{
+   using MeshType = typename DeviceMeshPointer::ObjectType;
+   Traverser< MeshType, EntityType > traverser;
+
+   Containers::Array< int, Devices::Cuda > array_boundary( deviceMeshPointer->template getEntitiesCount< EntityType >() );
+   Containers::Array< int, Devices::Cuda > array_interior( deviceMeshPointer->template getEntitiesCount< EntityType >() );
+   Containers::Array< int, Devices::Cuda > array_all     ( deviceMeshPointer->template getEntitiesCount< EntityType >() );
+
+   array_boundary.setValue( 0 );
+   array_interior.setValue( 0 );
+   array_all     .setValue( 0 );
+
+   traverser.template processBoundaryEntities< TestEntitiesProcessor >( deviceMeshPointer, array_boundary.getView() );
+   traverser.template processInteriorEntities< TestEntitiesProcessor >( deviceMeshPointer, array_interior.getView() );
+   traverser.template processAllEntities     < TestEntitiesProcessor >( deviceMeshPointer, array_all.getView() );
+
+   EXPECT_EQ( array_boundary, host_array_boundary );
+   EXPECT_EQ( array_interior, host_array_interior );
+   EXPECT_EQ( array_all,      host_array_all      );
+}
+
+TEST( MeshTest, RegularMeshOfQuadrilateralsTest )
+{
+   using QuadrilateralMeshEntityType = MeshEntity< TestQuadrilateralMeshConfig, Devices::Host, Topologies::Quadrilateral >;
+   using EdgeMeshEntityType = typename QuadrilateralMeshEntityType::SubentityTraits< 1 >::SubentityType;
+   using VertexMeshEntityType = typename QuadrilateralMeshEntityType::SubentityTraits< 0 >::SubentityType;
+
+   using PointType = typename VertexMeshEntityType::PointType;
+   static_assert( std::is_same< PointType, Containers::StaticVector< 2, RealType > >::value,
+                  "unexpected PointType" );
+
+   const IndexType xSize( 3 ), ySize( 4 );
+   const RealType width( 1.0 ), height( 1.0 );
+   const RealType hx( width / ( RealType ) xSize ),
+                  hy( height / ( RealType ) ySize );
+   const IndexType numberOfCells = xSize * ySize;
+   const IndexType numberOfVertices = ( xSize + 1 ) * ( ySize + 1 );
+
+   using TestQuadrilateralMesh = Mesh< TestQuadrilateralMeshConfig >;
+   Pointers::SharedPointer< TestQuadrilateralMesh > meshPointer;
+   MeshBuilder< TestQuadrilateralMesh > meshBuilder;
+   meshBuilder.setPointsCount( numberOfVertices );
+   meshBuilder.setCellsCount( numberOfCells );
+
+   /****
+    * Setup vertices
+    */
+   for( IndexType j = 0; j <= ySize; j++ )
+   for( IndexType i = 0; i <= xSize; i++ )
+      meshBuilder.setPoint( j * ( xSize + 1 ) + i, PointType( i * hx, j * hy ) );
+
+   /****
+    * Setup cells
+    */
+   IndexType cellIdx( 0 );
+   for( IndexType j = 0; j < ySize; j++ )
+   for( IndexType i = 0; i < xSize; i++ )
+   {
+      const IndexType vertex0 = j * ( xSize + 1 ) + i;
+      const IndexType vertex1 = j * ( xSize + 1 ) + i + 1;
+      const IndexType vertex2 = ( j + 1 ) * ( xSize + 1 ) + i + 1;
+      const IndexType vertex3 = ( j + 1 ) * ( xSize + 1 ) + i;
+
+      meshBuilder.getCellSeed( cellIdx   ).setCornerId( 0, vertex0 );
+      meshBuilder.getCellSeed( cellIdx   ).setCornerId( 1, vertex1 );
+      meshBuilder.getCellSeed( cellIdx   ).setCornerId( 2, vertex2 );
+      meshBuilder.getCellSeed( cellIdx++ ).setCornerId( 3, vertex3 );
+   }
+
+   ASSERT_TRUE( meshBuilder.build( *meshPointer ) );
+
+   // traversers for all test cases
+   Traverser< TestQuadrilateralMesh, QuadrilateralMeshEntityType > traverser_cells;
+   Traverser< TestQuadrilateralMesh, EdgeMeshEntityType > traverser_edges;
+   Traverser< TestQuadrilateralMesh, VertexMeshEntityType > traverser_vertices;
+
+   // arrays for all test cases
+   Containers::Array< int > array_cells_boundary( meshPointer->template getEntitiesCount< 2 >() );
+   Containers::Array< int > array_cells_interior( meshPointer->template getEntitiesCount< 2 >() );
+   Containers::Array< int > array_cells_all     ( meshPointer->template getEntitiesCount< 2 >() );
+
+   Containers::Array< int > array_edges_boundary( meshPointer->template getEntitiesCount< 1 >() );
+   Containers::Array< int > array_edges_interior( meshPointer->template getEntitiesCount< 1 >() );
+   Containers::Array< int > array_edges_all     ( meshPointer->template getEntitiesCount< 1 >() );
+
+   Containers::Array< int > array_vertices_boundary( meshPointer->template getEntitiesCount< 0 >() );
+   Containers::Array< int > array_vertices_interior( meshPointer->template getEntitiesCount< 0 >() );
+   Containers::Array< int > array_vertices_all     ( meshPointer->template getEntitiesCount< 0 >() );
+
+   // reset all arrays
+   array_cells_boundary.setValue( 0 );
+   array_cells_interior.setValue( 0 );
+   array_cells_all     .setValue( 0 );
+
+   array_edges_boundary.setValue( 0 );
+   array_edges_interior.setValue( 0 );
+   array_edges_all     .setValue( 0 );
+
+   array_vertices_boundary.setValue( 0 );
+   array_vertices_interior.setValue( 0 );
+   array_vertices_all     .setValue( 0 );
+
+   // traverse for all test cases
+   traverser_cells.template processBoundaryEntities< TestEntitiesProcessor >( meshPointer, array_cells_boundary.getView() );
+   traverser_cells.template processInteriorEntities< TestEntitiesProcessor >( meshPointer, array_cells_interior.getView() );
+   traverser_cells.template processAllEntities     < TestEntitiesProcessor >( meshPointer, array_cells_all.getView() );
+
+   traverser_edges.template processBoundaryEntities< TestEntitiesProcessor >( meshPointer, array_edges_boundary.getView() );
+   traverser_edges.template processInteriorEntities< TestEntitiesProcessor >( meshPointer, array_edges_interior.getView() );
+   traverser_edges.template processAllEntities     < TestEntitiesProcessor >( meshPointer, array_edges_all.getView() );
+
+   traverser_vertices.template processBoundaryEntities< TestEntitiesProcessor >( meshPointer, array_vertices_boundary.getView() );
+   traverser_vertices.template processInteriorEntities< TestEntitiesProcessor >( meshPointer, array_vertices_interior.getView() );
+   traverser_vertices.template processAllEntities     < TestEntitiesProcessor >( meshPointer, array_vertices_all.getView() );
+
+   // test traversing cells
+   for( IndexType j = 0; j < ySize; j++ )
+   for( IndexType i = 0; i < xSize; i++ )
+   {
+      const IndexType idx = j * xSize + i;
+      if( j == 0 || j == ySize - 1 || i == 0 || i == xSize - 1 ) {
+         EXPECT_EQ( array_cells_boundary[ idx ], 1 );
+         EXPECT_EQ( array_cells_interior[ idx ], 0 );
+      }
+      else {
+         EXPECT_EQ( array_cells_boundary[ idx ], 0 );
+         EXPECT_EQ( array_cells_interior[ idx ], 1 );
+      }
+      EXPECT_EQ( array_cells_all[ idx ], 1 );
+   }
+
+   // test traversing edges
+   // (edges are not numbered systematically, so we just compare with isBoundaryEntity)
+   for( IndexType idx = 0; idx < meshPointer->template getEntitiesCount< 1 >(); idx++ )
+   {
+      if( meshPointer->template isBoundaryEntity< 1 >( idx ) ) {
+         EXPECT_EQ( array_edges_boundary[ idx ], 1 );
+         EXPECT_EQ( array_edges_interior[ idx ], 0 );
+      }
+      else {
+         EXPECT_EQ( array_edges_boundary[ idx ], 0 );
+         EXPECT_EQ( array_edges_interior[ idx ], 1 );
+      }
+      EXPECT_EQ( array_edges_all[ idx ], 1 );
+   }
+
+   // test traversing vertices
+   for( IndexType j = 0; j <= ySize; j++ )
+   for( IndexType i = 0; i <= xSize; i++ )
+   {
+      const IndexType idx = j * (xSize + 1) + i;
+      if( j == 0 || j == ySize || i == 0 || i == xSize ) {
+         EXPECT_EQ( array_vertices_boundary[ idx ], 1 );
+         EXPECT_EQ( array_vertices_interior[ idx ], 0 );
+      }
+      else {
+         EXPECT_EQ( array_vertices_boundary[ idx ], 0 );
+         EXPECT_EQ( array_vertices_interior[ idx ], 1 );
+      }
+      EXPECT_EQ( array_vertices_all[ idx ], 1 );
+   }
+
+   // test traverser with CUDA
+#ifdef HAVE_CUDA
+   using DeviceMesh = Mesh< TestQuadrilateralMeshConfig, Devices::Cuda >;
+   Pointers::SharedPointer< DeviceMesh > deviceMeshPointer;
+   *deviceMeshPointer = *meshPointer;
+
+   testCudaTraverser< QuadrilateralMeshEntityType >( deviceMeshPointer, array_cells_boundary, array_cells_interior, array_cells_all );
+   testCudaTraverser< EdgeMeshEntityType          >( deviceMeshPointer, array_edges_boundary, array_edges_interior, array_edges_all );
+   testCudaTraverser< VertexMeshEntityType        >( deviceMeshPointer, array_vertices_boundary, array_vertices_interior, array_vertices_all );
+#endif
+}
+
+TEST( MeshTest, RegularMeshOfHexahedronsTest )
+{
+   using HexahedronMeshEntityType = MeshEntity< TestHexahedronMeshConfig, Devices::Host, Topologies::Hexahedron >;
+   using QuadrilateralMeshEntityType = typename HexahedronMeshEntityType::SubentityTraits< 2 >::SubentityType;
+   using EdgeMeshEntityType = typename HexahedronMeshEntityType::SubentityTraits< 1 >::SubentityType;
+   using VertexMeshEntityType = typename HexahedronMeshEntityType::SubentityTraits< 0 >::SubentityType;
+
+   using PointType = typename VertexMeshEntityType::PointType;
+   static_assert( std::is_same< PointType, Containers::StaticVector< 3, RealType > >::value,
+                  "unexpected PointType" );
+
+   const IndexType xSize( 3 ), ySize( 4 ), zSize( 5 );
+   const RealType width( 1.0 ), height( 1.0 ), depth( 1.0 );
+   const RealType hx( width / ( RealType ) xSize ),
+                  hy( height / ( RealType ) ySize ),
+                  hz( depth / ( RealType ) zSize );
+   const IndexType numberOfCells = xSize * ySize * zSize;
+   const IndexType numberOfVertices = ( xSize + 1 ) * ( ySize + 1 ) * ( zSize + 1 );
+
+   using TestHexahedronMesh = Mesh< TestHexahedronMeshConfig >;
+   Pointers::SharedPointer< TestHexahedronMesh > meshPointer;
+   MeshBuilder< TestHexahedronMesh > meshBuilder;
+   meshBuilder.setPointsCount( numberOfVertices );
+   meshBuilder.setCellsCount( numberOfCells );
+
+   /****
+    * Setup vertices
+    */
+   for( IndexType k = 0; k <= zSize; k++ )
+   for( IndexType j = 0; j <= ySize; j++ )
+   for( IndexType i = 0; i <= xSize; i++ )
+      meshBuilder.setPoint( k * ( xSize + 1 ) * ( ySize + 1 ) + j * ( xSize + 1 ) + i, PointType( i * hx, j * hy, k * hz ) );
+
+   /****
+    * Setup cells
+    */
+   IndexType cellIdx( 0 );
+   for( IndexType k = 0; k < zSize; k++ )
+   for( IndexType j = 0; j < ySize; j++ )
+   for( IndexType i = 0; i < xSize; i++ )
+   {
+      const IndexType vertex0 = k * ( xSize + 1 ) * ( ySize + 1 ) + j * ( xSize + 1 ) + i;
+      const IndexType vertex1 = k * ( xSize + 1 ) * ( ySize + 1 ) + j * ( xSize + 1 ) + i + 1;
+      const IndexType vertex2 = k * ( xSize + 1 ) * ( ySize + 1 ) + ( j + 1 ) * ( xSize + 1 ) + i + 1;
+      const IndexType vertex3 = k * ( xSize + 1 ) * ( ySize + 1 ) + ( j + 1 ) * ( xSize + 1 ) + i;
+      const IndexType vertex4 = ( k + 1 ) * ( xSize + 1 ) * ( ySize + 1 ) + j * ( xSize + 1 ) + i;
+      const IndexType vertex5 = ( k + 1 ) * ( xSize + 1 ) * ( ySize + 1 ) + j * ( xSize + 1 ) + i + 1;
+      const IndexType vertex6 = ( k + 1 ) * ( xSize + 1 ) * ( ySize + 1 ) + ( j + 1 ) * ( xSize + 1 ) + i + 1;
+      const IndexType vertex7 = ( k + 1 ) * ( xSize + 1 ) * ( ySize + 1 ) + ( j + 1 ) * ( xSize + 1 ) + i;
+
+      meshBuilder.getCellSeed( cellIdx   ).setCornerId( 0, vertex0 );
+      meshBuilder.getCellSeed( cellIdx   ).setCornerId( 1, vertex1 );
+      meshBuilder.getCellSeed( cellIdx   ).setCornerId( 2, vertex2 );
+      meshBuilder.getCellSeed( cellIdx   ).setCornerId( 3, vertex3 );
+      meshBuilder.getCellSeed( cellIdx   ).setCornerId( 4, vertex4 );
+      meshBuilder.getCellSeed( cellIdx   ).setCornerId( 5, vertex5 );
+      meshBuilder.getCellSeed( cellIdx   ).setCornerId( 6, vertex6 );
+      meshBuilder.getCellSeed( cellIdx++ ).setCornerId( 7, vertex7 );
+   }
+
+   ASSERT_TRUE( meshBuilder.build( *meshPointer ) );
+
+   // traversers for all test cases
+   Traverser< TestHexahedronMesh, HexahedronMeshEntityType > traverser_cells;
+   Traverser< TestHexahedronMesh, QuadrilateralMeshEntityType > traverser_faces;
+   Traverser< TestHexahedronMesh, EdgeMeshEntityType > traverser_edges;
+   Traverser< TestHexahedronMesh, VertexMeshEntityType > traverser_vertices;
+
+   // arrays for all test cases
+   Containers::Array< int > array_cells_boundary( meshPointer->template getEntitiesCount< 3 >() );
+   Containers::Array< int > array_cells_interior( meshPointer->template getEntitiesCount< 3 >() );
+   Containers::Array< int > array_cells_all     ( meshPointer->template getEntitiesCount< 3 >() );
+
+   Containers::Array< int > array_faces_boundary( meshPointer->template getEntitiesCount< 2 >() );
+   Containers::Array< int > array_faces_interior( meshPointer->template getEntitiesCount< 2 >() );
+   Containers::Array< int > array_faces_all     ( meshPointer->template getEntitiesCount< 2 >() );
+
+   Containers::Array< int > array_edges_boundary( meshPointer->template getEntitiesCount< 1 >() );
+   Containers::Array< int > array_edges_interior( meshPointer->template getEntitiesCount< 1 >() );
+   Containers::Array< int > array_edges_all     ( meshPointer->template getEntitiesCount< 1 >() );
+
+   Containers::Array< int > array_vertices_boundary( meshPointer->template getEntitiesCount< 0 >() );
+   Containers::Array< int > array_vertices_interior( meshPointer->template getEntitiesCount< 0 >() );
+   Containers::Array< int > array_vertices_all     ( meshPointer->template getEntitiesCount< 0 >() );
+
+   // reset all arrays
+   array_cells_boundary.setValue( 0 );
+   array_cells_interior.setValue( 0 );
+   array_cells_all     .setValue( 0 );
+
+   array_faces_boundary.setValue( 0 );
+   array_faces_interior.setValue( 0 );
+   array_faces_all     .setValue( 0 );
+
+   array_edges_boundary.setValue( 0 );
+   array_edges_interior.setValue( 0 );
+   array_edges_all     .setValue( 0 );
+
+   array_vertices_boundary.setValue( 0 );
+   array_vertices_interior.setValue( 0 );
+   array_vertices_all     .setValue( 0 );
+
+   // traverse for all test cases
+   traverser_cells.template processBoundaryEntities< TestEntitiesProcessor >( meshPointer, array_cells_boundary.getView() );
+   traverser_cells.template processInteriorEntities< TestEntitiesProcessor >( meshPointer, array_cells_interior.getView() );
+   traverser_cells.template processAllEntities     < TestEntitiesProcessor >( meshPointer, array_cells_all.getView() );
+
+   traverser_faces.template processBoundaryEntities< TestEntitiesProcessor >( meshPointer, array_faces_boundary.getView() );
+   traverser_faces.template processInteriorEntities< TestEntitiesProcessor >( meshPointer, array_faces_interior.getView() );
+   traverser_faces.template processAllEntities     < TestEntitiesProcessor >( meshPointer, array_faces_all.getView() );
+
+   traverser_edges.template processBoundaryEntities< TestEntitiesProcessor >( meshPointer, array_edges_boundary.getView() );
+   traverser_edges.template processInteriorEntities< TestEntitiesProcessor >( meshPointer, array_edges_interior.getView() );
+   traverser_edges.template processAllEntities     < TestEntitiesProcessor >( meshPointer, array_edges_all.getView() );
+
+   traverser_vertices.template processBoundaryEntities< TestEntitiesProcessor >( meshPointer, array_vertices_boundary.getView() );
+   traverser_vertices.template processInteriorEntities< TestEntitiesProcessor >( meshPointer, array_vertices_interior.getView() );
+   traverser_vertices.template processAllEntities     < TestEntitiesProcessor >( meshPointer, array_vertices_all.getView() );
+
+   // test traversing cells
+   for( IndexType k = 0; k < zSize; k++ )
+   for( IndexType j = 0; j < ySize; j++ )
+   for( IndexType i = 0; i < xSize; i++ )
+   {
+      const IndexType idx = k * xSize * ySize + j * xSize + i;
+      if( k == 0 || k == zSize - 1 || j == 0 || j == ySize - 1 || i == 0 || i == xSize - 1 ) {
+         EXPECT_EQ( array_cells_boundary[ idx ], 1 );
+         EXPECT_EQ( array_cells_interior[ idx ], 0 );
+      }
+      else {
+         EXPECT_EQ( array_cells_boundary[ idx ], 0 );
+         EXPECT_EQ( array_cells_interior[ idx ], 1 );
+      }
+      EXPECT_EQ( array_cells_all[ idx ], 1 );
+   }
+
+   // test traversing faces
+   // (faces are not numbered systematically, so we just compare with isBoundaryEntity)
+   for( IndexType idx = 0; idx < meshPointer->template getEntitiesCount< 2 >(); idx++ )
+   {
+      if( meshPointer->template isBoundaryEntity< 2 >( idx ) ) {
+         EXPECT_EQ( array_faces_boundary[ idx ], 1 );
+         EXPECT_EQ( array_faces_interior[ idx ], 0 );
+      }
+      else {
+         EXPECT_EQ( array_faces_boundary[ idx ], 0 );
+         EXPECT_EQ( array_faces_interior[ idx ], 1 );
+      }
+      EXPECT_EQ( array_faces_all[ idx ], 1 );
+   }
+
+   // test traversing edges
+   // (edges are not numbered systematically, so we just compare with isBoundaryEntity)
+   for( IndexType idx = 0; idx < meshPointer->template getEntitiesCount< 1 >(); idx++ )
+   {
+      if( meshPointer->template isBoundaryEntity< 1 >( idx ) ) {
+         EXPECT_EQ( array_edges_boundary[ idx ], 1 );
+         EXPECT_EQ( array_edges_interior[ idx ], 0 );
+      }
+      else {
+         EXPECT_EQ( array_edges_boundary[ idx ], 0 );
+         EXPECT_EQ( array_edges_interior[ idx ], 1 );
+      }
+      EXPECT_EQ( array_edges_all[ idx ], 1 );
+   }
+
+   // test traversing vertices
+   for( IndexType k = 0; k <= zSize; k++ )
+   for( IndexType j = 0; j <= ySize; j++ )
+   for( IndexType i = 0; i <= xSize; i++ )
+   {
+      const IndexType idx = k * (xSize + 1) * (ySize + 1) + j * (xSize + 1) + i;
+      if( k == 0 || k == zSize || j == 0 || j == ySize || i == 0 || i == xSize ) {
+         EXPECT_EQ( array_vertices_boundary[ idx ], 1 );
+         EXPECT_EQ( array_vertices_interior[ idx ], 0 );
+      }
+      else {
+         EXPECT_EQ( array_vertices_boundary[ idx ], 0 );
+         EXPECT_EQ( array_vertices_interior[ idx ], 1 );
+      }
+      EXPECT_EQ( array_vertices_all[ idx ], 1 );
+   }
+
+   // test traverser with CUDA
+#ifdef HAVE_CUDA
+   using DeviceMesh = Mesh< TestHexahedronMeshConfig, Devices::Cuda >;
+   Pointers::SharedPointer< DeviceMesh > deviceMeshPointer;
+   *deviceMeshPointer = *meshPointer;
+
+   testCudaTraverser< HexahedronMeshEntityType    >( deviceMeshPointer, array_cells_boundary, array_cells_interior, array_cells_all );
+   testCudaTraverser< QuadrilateralMeshEntityType >( deviceMeshPointer, array_faces_boundary, array_faces_interior, array_faces_all );
+   testCudaTraverser< EdgeMeshEntityType          >( deviceMeshPointer, array_edges_boundary, array_edges_interior, array_edges_all );
+   testCudaTraverser< VertexMeshEntityType        >( deviceMeshPointer, array_vertices_boundary, array_vertices_interior, array_vertices_all );
+#endif
+}
+
+} // namespace MeshTest
+
+#endif
-- 
GitLab