diff --git a/src/Benchmarks/CMakeLists.txt b/src/Benchmarks/CMakeLists.txt index 0fc8e0f023d8e4a08ee652cc0474643f8a32e1dc..57e8b18615e9f46dda9e804d85a80f0cb6621e69 100644 --- a/src/Benchmarks/CMakeLists.txt +++ b/src/Benchmarks/CMakeLists.txt @@ -7,3 +7,4 @@ add_subdirectory( LinearSolvers ) add_subdirectory( ODESolvers ) add_subdirectory( Sorting ) add_subdirectory( Traversers ) +add_subdirectory( Mesh ) diff --git a/src/Benchmarks/Mesh/CMakeLists.txt b/src/Benchmarks/Mesh/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..b07ba5ef0bf36f68631c113ef98e42f43e85f529 --- /dev/null +++ b/src/Benchmarks/Mesh/CMakeLists.txt @@ -0,0 +1,35 @@ +if( BUILD_CUDA ) + CUDA_ADD_EXECUTABLE( tnl-benchmark-mesh-cuda tnl-benchmark-mesh.cu ) + + find_package( tinyxml2 QUIET ) + if( tinyxml2_FOUND ) + target_compile_definitions(tnl-benchmark-mesh-cuda PUBLIC "-DHAVE_TINYXML2") + target_link_libraries(tnl-benchmark-mesh-cuda tinyxml2::tinyxml2) + endif() + + find_package( ZLIB ) + if( ZLIB_FOUND ) + target_compile_definitions(tnl-benchmark-mesh-cuda PUBLIC "-DHAVE_ZLIB") + target_include_directories(tnl-benchmark-mesh-cuda PUBLIC ${ZLIB_INCLUDE_DIRS}) + target_link_libraries(tnl-benchmark-mesh-cuda ${ZLIB_LIBRARIES}) + endif() + + install( TARGETS tnl-benchmark-mesh-cuda RUNTIME DESTINATION bin ) +endif() + +ADD_EXECUTABLE( tnl-benchmark-mesh tnl-benchmark-mesh.cpp ) + +find_package( tinyxml2 QUIET ) +if( tinyxml2_FOUND ) + target_compile_definitions(tnl-benchmark-mesh PUBLIC "-DHAVE_TINYXML2") + target_link_libraries(tnl-benchmark-mesh tinyxml2::tinyxml2) +endif() + +find_package( ZLIB ) +if( ZLIB_FOUND ) + target_compile_definitions(tnl-benchmark-mesh PUBLIC "-DHAVE_ZLIB") + target_include_directories(tnl-benchmark-mesh PUBLIC ${ZLIB_INCLUDE_DIRS}) + target_link_libraries(tnl-benchmark-mesh ${ZLIB_LIBRARIES}) +endif() + +install( TARGETS tnl-benchmark-mesh RUNTIME DESTINATION bin ) diff --git a/src/Benchmarks/Mesh/MemoryInfo.h b/src/Benchmarks/Mesh/MemoryInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..3325dde2287eeb498ff18a6520e7f7a7be3c1c1e --- /dev/null +++ b/src/Benchmarks/Mesh/MemoryInfo.h @@ -0,0 +1,195 @@ +#pragma once + +// References: +// - https://stackoverflow.com/a/64166/4180822 +// - https://lemire.me/blog/2020/03/03/calling-free-or-delete/ +// - https://stackoverflow.com/questions/15529643/what-does-malloc-trim0-really-mean + +#include +#include +#include + +#include +#include +#include + +inline long +getTotalVirtualMemory() +{ + struct sysinfo memInfo; + sysinfo (&memInfo); + + long totalVirtualMem = memInfo.totalram; + // Add other values in next statement to avoid int overflow on right hand side... + totalVirtualMem += memInfo.totalswap; + totalVirtualMem *= memInfo.mem_unit; + + return totalVirtualMem; +} + +inline long +getUsedVirtualMemory() +{ + struct sysinfo memInfo; + sysinfo (&memInfo); + + long virtualMemUsed = memInfo.totalram - memInfo.freeram; + // Add other values in next statement to avoid int overflow on right hand side... + virtualMemUsed += memInfo.totalswap - memInfo.freeswap; + virtualMemUsed *= memInfo.mem_unit; + + return virtualMemUsed; +} + +inline long +parseLine(char* line) +{ + // This assumes that a digit will be found and the line ends in " kB". + int i = strlen(line); + const char* p = line; + while (*p <'0' || *p > '9') p++; + line[i-3] = '\0'; + return atol(p); +} + +// virtual memory currently used by the calling process +inline long +getSelfVirtualMemory() +{ + // explicitly release unused memory + malloc_trim(0); + + FILE* file = fopen("/proc/self/status", "r"); + long result = -1; + char line[128]; + + while (fgets(line, 128, file) != NULL){ + if (strncmp(line, "VmSize:", 7) == 0){ + // convert from kB to B + result = parseLine(line) * 1024; + break; + } + } + fclose(file); + return result; +} + +inline long +getTotalPhysicalMemory() +{ + struct sysinfo memInfo; + sysinfo (&memInfo); + + long totalPhysMem = memInfo.totalram; + //Multiply in next statement to avoid int overflow on right hand side... + totalPhysMem *= memInfo.mem_unit; + + return totalPhysMem; +} + +inline long +getUsedPhysicalMemory() +{ + struct sysinfo memInfo; + sysinfo (&memInfo); + + long physMemUsed = memInfo.totalram - memInfo.freeram; + //Multiply in next statement to avoid int overflow on right hand side... + physMemUsed *= memInfo.mem_unit; + + return physMemUsed; +} + +inline long +getSelfPhysicalMemory() +{ + // explicitly release unused memory + malloc_trim(0); + + FILE* file = fopen("/proc/self/status", "r"); + long result = -1; + char line[128]; + + while (fgets(line, 128, file) != NULL){ + if (strncmp(line, "VmRSS:", 6) == 0){ + // convert from kB to B + result = parseLine(line) * 1024; + break; + } + } + fclose(file); + return result; +} + + +#include +#include +#include + +struct MemoryBenchmarkResult +: public TNL::Benchmarks::BenchmarkResult +{ + using HeaderElements = TNL::Benchmarks::Logging::HeaderElements; + using RowElements = TNL::Benchmarks::Logging::RowElements; + + double memory = std::numeric_limits::quiet_NaN(); + double memstddev = std::numeric_limits::quiet_NaN(); + + virtual HeaderElements getTableHeader() const override + { + return HeaderElements({ "time", "stddev", "stddev/time", "bandwidth", "speedup", "memory", "memstddev", "memstddev/memory" }); + } + + virtual RowElements getRowElements() const override + { + RowElements elements; + elements << time << stddev << stddev / time << bandwidth; + if( speedup != 0 ) + elements << speedup; + else + elements << "N/A"; + elements << memory << memstddev << memstddev / memory; + return elements; + } +}; + +template< long MAX_COPIES = 10, typename Mesh > +MemoryBenchmarkResult +testMemoryUsage( const TNL::Config::ParameterContainer& parameters, + const Mesh& mesh ) +{ + const size_t memoryLimit = parameters.getParameter< size_t >( "mem-limit" ) * 1024 * 1024; + TNL::Containers::StaticVector< MAX_COPIES, Mesh > meshes; + TNL::Containers::StaticVector< MAX_COPIES, double > data; + data.setValue( 0 ); + + long prevCheck = getSelfPhysicalMemory(); + meshes[0] = mesh; + long check = getSelfPhysicalMemory(); + data[0] = check - prevCheck; + prevCheck = check; + const int copies = TNL::min( memoryLimit / data[0], MAX_COPIES - 1 ) + 1; + + for( int i = 1; i < copies; i++ ) { + meshes[i] = mesh; + check = getSelfPhysicalMemory(); + data[i] = check - prevCheck; + prevCheck = check; + } + + MemoryBenchmarkResult result; + + const double mean = TNL::sum( data ) / (double) copies; + result.memory = mean / 1024.0 / 1024.0; // MiB + + if( copies > 1 ) { + for( int i = copies; i < MAX_COPIES; i++ ) { + data[i] = mean; + } + + const double stddev = 1.0 / std::sqrt( copies ) * TNL::l2Norm( data - mean ); + result.memstddev = stddev / 1024.0 / 1024.0; // MiB + } + + return result; +} diff --git a/src/Benchmarks/Mesh/MeshBenchmarks.h b/src/Benchmarks/Mesh/MeshBenchmarks.h new file mode 100644 index 0000000000000000000000000000000000000000..19a9ddda4b5139c36a9bab7552aca80f469e6026 --- /dev/null +++ b/src/Benchmarks/Mesh/MeshBenchmarks.h @@ -0,0 +1,396 @@ +/*************************************************************************** + MeshBenchmarks.h - description + ------------------- + begin : Nov 21, 2017 + copyright : (C) 2017 by Tomas Oberhuber et al. + email : tomas.oberhuber@fjfi.cvut.cz + ***************************************************************************/ + +/* See Copyright Notice in tnl/Copyright */ + +// Implemented by: Ján Bobot, Jakub Klinkovský + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MeshConfigs.h" +#include "MemoryInfo.h" + +using namespace TNL; +using namespace TNL::Meshes; +using namespace TNL::Meshes::Readers; +using namespace TNL::Benchmarks; + +template< typename Device > +bool checkDevice( const Config::ParameterContainer& parameters ) +{ + const String device = parameters.getParameter< String >( "devices" ); + if( device == "all" ) + return true; + if( std::is_same< Device, Devices::Host >::value && device == "host" ) + return true; + if( std::is_same< Device, Devices::Cuda >::value && device == "cuda" ) + return true; + return false; +} + +std::string removeNamespaces( const String & topology ) +{ + std::size_t found = topology.find_last_of("::"); + return topology.substr( found + 1 ); +} + +template< typename Mesh > +struct MeshBenchmarks +{ + static_assert( std::is_same< typename Mesh::DeviceType, Devices::Host >::value, "The mesh should be loaded on the host." ); + + static bool run( Benchmark<> & benchmark, const Config::ParameterContainer & parameters ) + { + Logging::MetadataColumns metadataColumns = { + // {"mesh-file", meshFile}, + {"config", Mesh::Config::getConfigType()}, + //{"topology", removeNamespaces( getType< typename Mesh::Config::CellTopology >() ) }, + //{"space dim", std::to_string( Mesh::Config::spaceDimension )}, + //{"real", getType< typename Mesh::RealType >()}, + //{"gid_t", getType< typename Mesh::GlobalIndexType >()}, + //{"lid_t", getType< typename Mesh::LocalIndexType >()} + }; + benchmark.setMetadataColumns( metadataColumns ); + + const String & meshFile = parameters.getParameter< String >( "mesh-file" ); + auto reader = getMeshReader( meshFile, "auto" ); + Mesh mesh; + + try { + reader->loadMesh( mesh ); + } + catch( const Meshes::Readers::MeshReaderError& e ) { + std::cerr << "Failed to load mesh from file '" << meshFile << "'." << std::endl; + return false; + } + + dispatchTests( benchmark, parameters, mesh, reader ); + + return true; + } + + static void dispatchTests( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const Mesh & mesh, std::shared_ptr< MeshReader > reader ) + { + ReaderDispatch::exec( benchmark, parameters, reader ); + InitDispatch::exec( benchmark, parameters, reader ); + DecompositionDispatch::exec( benchmark, parameters, mesh ); + PlanarDispatch::exec( benchmark, parameters, mesh ); + MeasuresDispatch::exec( benchmark, parameters, mesh ); + MemoryDispatch::exec( benchmark, parameters, mesh ); + CopyDispatch::exec( benchmark, parameters, mesh ); + } + + struct ReaderDispatch + { + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) + { + benchmark.setOperation( String( "Reader" ) ); + benchmark_reader( benchmark, parameters, reader ); + } + }; + + struct InitDispatch + { + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) + { + benchmark.setOperation( String( "Init" ) ); + benchmark_init( benchmark, parameters, reader ); + } + }; + + struct DecompositionDispatch + { + // Polygonal Mesh + template< typename M, + std::enable_if_t< std::is_same< typename M::Config::CellTopology, Topologies::Polygon >::value, bool > = true > + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + benchmark.setOperation( String( "Decomposition (c)" ) ); + benchmark_decomposition< EntityDecomposerVersion::ConnectEdgesToCentroid >( benchmark, parameters, mesh_src ); + + benchmark.setOperation( String( "Decomposition (p)" ) ); + benchmark_decomposition< EntityDecomposerVersion::ConnectEdgesToPoint >( benchmark, parameters, mesh_src ); + } + + // Polyhedral Mesh + template< typename M, + std::enable_if_t< std::is_same< typename M::Config::CellTopology, Topologies::Polyhedron >::value, bool > = true > + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + benchmark.setOperation( String( "Decomposition (cc)" ) ); + benchmark_decomposition< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToCentroid >( benchmark, parameters, mesh_src ); + + benchmark.setOperation( String( "Decomposition (cp)" ) ); + benchmark_decomposition< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToPoint >( benchmark, parameters, mesh_src ); + + benchmark.setOperation( String( "Decomposition (pc)" ) ); + benchmark_decomposition< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToCentroid >( benchmark, parameters, mesh_src ); + + benchmark.setOperation( String( "Decomposition (pp)" ) ); + benchmark_decomposition< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToPoint >( benchmark, parameters, mesh_src ); + } + + // Other than Polygonal and Polyhedral Mesh + template< typename M, + std::enable_if_t< ! std::is_same< typename M::Config::CellTopology, Topologies::Polygon >::value && + ! std::is_same< typename M::Config::CellTopology, Topologies::Polyhedron >::value, bool > = true > + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + } + }; + + struct PlanarDispatch + { + template< typename M, + std::enable_if_t< M::Config::spaceDimension == 3 && + (std::is_same< typename M::Config::CellTopology, Topologies::Polygon >::value || + std::is_same< typename M::Config::CellTopology, Topologies::Polyhedron >::value ), bool > = true > + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + benchmark.setOperation( String( "Planar Correction (c)" ) ); + benchmark_planar< EntityDecomposerVersion::ConnectEdgesToCentroid >( benchmark, parameters, mesh_src ); + + benchmark.setOperation( String( "Planar Correction (p)" ) ); + benchmark_planar< EntityDecomposerVersion::ConnectEdgesToPoint >( benchmark, parameters, mesh_src ); + } + + template< typename M, + std::enable_if_t< M::Config::spaceDimension < 3 || + (! std::is_same< typename M::Config::CellTopology, Topologies::Polygon >::value && + ! std::is_same< typename M::Config::CellTopology, Topologies::Polyhedron >::value ), bool > = true > + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + } + }; + + struct MeasuresDispatch + { + template< typename M > + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh ) + { + benchmark.setOperation( String("Measures") ); + benchmark_measures< Devices::Host >( benchmark, parameters, mesh ); + #ifdef HAVE_CUDA + benchmark_measures< Devices::Cuda >( benchmark, parameters, mesh ); + #endif + } + }; + + struct MemoryDispatch + { + template< typename M > + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer& parameters, const M& mesh_src ) + { + benchmark.setOperation( String("Memory") ); + benchmark_memory( benchmark, parameters, mesh_src ); + } + }; + + struct CopyDispatch + { + template< typename M > + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + #ifdef HAVE_CUDA + benchmark.setOperation( String("Copy CPU->GPU") ); + benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, mesh_src ); + benchmark.setOperation( String("Copy GPU->CPU") ); + benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, mesh_src ); + #endif + } + }; + + static void benchmark_reader( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) + { + if( ! checkDevice< Devices::Host >( parameters ) ) + return; + + auto reset = [&]() { + reader->reset(); + }; + + auto benchmark_func = [&] () { + reader->detectMesh(); + }; + + benchmark.time< Devices::Host >( reset, + "CPU", + benchmark_func ); + } + + static void benchmark_init( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) + { + if( ! checkDevice< Devices::Host >( parameters ) ) + return; + + auto reset = [&]() { + reader->detectMesh(); + }; + + auto benchmark_func = [&] () { + Mesh mesh; + reader->loadMesh( mesh ); + }; + + benchmark.time< Devices::Host >( reset, + "CPU", + benchmark_func ); + } + + template< EntityDecomposerVersion DecomposerVersion, + EntityDecomposerVersion SubDecomposerVersion = EntityDecomposerVersion::ConnectEdgesToPoint, + typename M > + static void benchmark_decomposition( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + // skip benchmarks on devices which the user did not select + if( ! checkDevice< Devices::Host >( parameters ) ) + return; + + auto benchmark_func = [&] () { + auto meshBuilder = decomposeMesh< DecomposerVersion, SubDecomposerVersion >( mesh_src ); + }; + + benchmark.time< Devices::Host >( "CPU", + benchmark_func ); + } + + template< EntityDecomposerVersion DecomposerVersion, + typename M, + std::enable_if_t< M::Config::spaceDimension == 3 && + (std::is_same< typename M::Config::CellTopology, Topologies::Polygon >::value || + std::is_same< typename M::Config::CellTopology, Topologies::Polyhedron >::value ), bool > = true > + static void benchmark_planar( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + if( ! checkDevice< Devices::Host >( parameters ) ) + return; + + auto benchmark_func = [&] () { + auto meshBuilder = planarCorrection< DecomposerVersion >( mesh_src ); + }; + + benchmark.time< Devices::Host >( "CPU", + benchmark_func ); + } + + template< typename Device, + typename M > + static void benchmark_measures( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + using Real = typename M::RealType; + using Index = typename M::GlobalIndexType; + using DeviceMesh = Meshes::Mesh< typename M::Config, Device >; + + // skip benchmarks on devices which the user did not select + if( ! checkDevice< Device >( parameters ) ) + return; + + const Index entitiesCount = mesh_src.template getEntitiesCount< M::getMeshDimension() >(); + + const DeviceMesh mesh = mesh_src; + Pointers::DevicePointer< const DeviceMesh > meshPointer( mesh ); + Containers::Array< Real, Device, Index > measures; + measures.setSize( entitiesCount ); + + auto kernel_measures = [] __cuda_callable__ + ( Index i, + const DeviceMesh* mesh, + Real* array ) + { + const auto& entity = mesh->template getEntity< M::getMeshDimension() >( i ); + array[ i ] = getEntityMeasure( *mesh, entity ); + }; + + auto reset = [&]() { + measures.setValue( 0.0 ); + }; + + auto benchmark_func = [&] () { + Algorithms::ParallelFor< Device >::exec( + (Index) 0, entitiesCount, + kernel_measures, + &meshPointer.template getData< Device >(), + measures.getData() ); + }; + + benchmark.time< Device >( reset, + (std::is_same< Device, Devices::Host >::value) ? "CPU" : "GPU", + benchmark_func ); + } + + template< typename M > + static void benchmark_memory( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + if( ! checkDevice< Devices::Host >( parameters ) ) + return; + + MemoryBenchmarkResult memResult = testMemoryUsage( parameters, mesh_src ); + auto noop = [](){}; + benchmark.time< TNL::Devices::Host >( "CPU", noop, memResult ); + } + + template< typename DeviceFrom, + typename DeviceTo, + typename M > + static void benchmark_copy( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + using MeshFrom = Meshes::Mesh< typename M::Config, DeviceFrom >; + using MeshTo = Meshes::Mesh< typename M::Config, DeviceTo >; + using Device = typename std::conditional_t< std::is_same< DeviceFrom, Devices::Host >::value && + std::is_same< DeviceTo, Devices::Host >::value, + Devices::Host, + Devices::Cuda >; + + // skip benchmarks on devices which the user did not select + if( ! checkDevice< Device >( parameters ) ) + return; + + const MeshFrom meshFrom = mesh_src; + + auto benchmark_func = [&] () { + MeshTo meshTo = meshFrom; + }; + + benchmark.time< Device >( [] () {}, + (std::is_same< Device, Devices::Host >::value) ? "CPU" : "GPU", + benchmark_func ); + } +}; + +template< template< typename, int, typename, typename, typename > class ConfigTemplate, + typename CellTopology, + int SpaceDimension, + typename Real, + typename GlobalIndex, + typename LocalIndex > +struct MeshBenchmarksRunner +{ + static bool + run( Benchmark<> & benchmark, + const Config::ParameterContainer & parameters ) + { + using Config = ConfigTemplate< CellTopology, SpaceDimension, Real, GlobalIndex, LocalIndex >; + using MeshType = Mesh< Config, Devices::Host >; + return MeshBenchmarks< MeshType >::run( benchmark, parameters ); + } +}; diff --git a/src/Benchmarks/Mesh/MeshConfigs.h b/src/Benchmarks/Mesh/MeshConfigs.h new file mode 100644 index 0000000000000000000000000000000000000000..765ff58ef5e4fcf35e8c320d7372dfc079d970ab --- /dev/null +++ b/src/Benchmarks/Mesh/MeshConfigs.h @@ -0,0 +1,138 @@ +/*************************************************************************** + MeshConfigs.h - description + ------------------- + begin : Dec 12, 2017 + copyright : (C) 2017 by Tomas Oberhuber et al. + email : tomas.oberhuber@fjfi.cvut.cz + ***************************************************************************/ + +/* See Copyright Notice in tnl/Copyright */ + +// Implemented by: Jakub Klinkovsky + +#pragma once + +#include +#include + +template< typename Cell, + int SpaceDimension = Cell::dimension, + typename Real = double, + typename GlobalIndex = int, + typename LocalIndex = GlobalIndex > +struct FullConfig +{ + using CellTopology = Cell; + using RealType = Real; + using GlobalIndexType = GlobalIndex; + using LocalIndexType = LocalIndex; + + static constexpr int spaceDimension = SpaceDimension; + static constexpr int meshDimension = Cell::dimension; + + static TNL::String getConfigType() + { + return "Full"; + } + + /**** + * Storage of subentities of mesh entities. + */ + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) + { + return true; + } + + /**** + * Storage of superentities of mesh entities. + */ + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) + { + return true; + } + + /**** + * Storage of mesh entity tags. Boundary tags are necessary for the mesh traverser. + */ + static constexpr bool entityTagsStorage( int entityDimension ) + { + return true; + } + + /**** + * Storage of the dual graph. + * + * If enabled, links from vertices to cells must be stored. + */ + static constexpr bool dualGraphStorage() + { + return true; + } + + /**** + * Cells must have at least this number of common vertices to be considered + * as neighbors in the dual graph. + */ + static constexpr int dualGraphMinCommonVertices = meshDimension; +}; + +template< typename Cell, + int SpaceDimension = Cell::dimension, + typename Real = double, + typename GlobalIndex = int, + typename LocalIndex = GlobalIndex > +struct MinimalConfig +{ + using CellTopology = Cell; + using RealType = Real; + using GlobalIndexType = GlobalIndex; + using LocalIndexType = LocalIndex; + + static constexpr int spaceDimension = SpaceDimension; + static constexpr int meshDimension = Cell::dimension; + + static TNL::String getConfigType() + { + return "Minimal"; + } + + /**** + * Storage of subentities of mesh entities. + */ + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) + { + return subentityDimension == 0 || ( subentityDimension == meshDimension - 1 && entityDimension == meshDimension ); + } + + /**** + * Storage of superentities of mesh entities. + */ + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) + { + return ( entityDimension == 0 || entityDimension == meshDimension - 1 ) && superentityDimension == meshDimension; + } + + /**** + * Storage of mesh entity tags. Boundary tags are necessary for the mesh traverser. + */ + static constexpr bool entityTagsStorage( int entityDimension ) + { + return false; + } + + /**** + * Storage of the dual graph. + * + * If enabled, links from vertices to cells must be stored. + */ + static constexpr bool dualGraphStorage() + { + return false; + } + + /**** + * Cells must have at least this number of common vertices to be considered + * as neighbors in the dual graph. + */ + static constexpr int dualGraphMinCommonVertices = meshDimension; +}; diff --git a/src/Benchmarks/Mesh/tnl-benchmark-mesh.cpp b/src/Benchmarks/Mesh/tnl-benchmark-mesh.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b19887b2ba25407c27945289b89b0cd027b61fde --- /dev/null +++ b/src/Benchmarks/Mesh/tnl-benchmark-mesh.cpp @@ -0,0 +1 @@ +#include "tnl-benchmark-mesh.h" diff --git a/src/Benchmarks/Mesh/tnl-benchmark-mesh.cu b/src/Benchmarks/Mesh/tnl-benchmark-mesh.cu new file mode 100644 index 0000000000000000000000000000000000000000..b19887b2ba25407c27945289b89b0cd027b61fde --- /dev/null +++ b/src/Benchmarks/Mesh/tnl-benchmark-mesh.cu @@ -0,0 +1 @@ +#include "tnl-benchmark-mesh.h" diff --git a/src/Benchmarks/Mesh/tnl-benchmark-mesh.h b/src/Benchmarks/Mesh/tnl-benchmark-mesh.h new file mode 100644 index 0000000000000000000000000000000000000000..56b3a866d6b9158c2e876c4fc75511a67ca5a5c0 --- /dev/null +++ b/src/Benchmarks/Mesh/tnl-benchmark-mesh.h @@ -0,0 +1,148 @@ +/*************************************************************************** + tnl-benchmark-mesh.h - description + ------------------- + begin : Nov 12, 2017 + copyright : (C) 2017 by Tomas Oberhuber et al. + email : tomas.oberhuber@fjfi.cvut.cz + ***************************************************************************/ + +/* See Copyright Notice in tnl/Copyright */ + +// Implemented by: Ján Bobot, Jakub Klinkovský + +#pragma once + +#include +#include +#include +#include +#include + +#include "MeshBenchmarks.h" + + +using namespace TNL; +using namespace TNL::Meshes; +using namespace TNL::Meshes::Readers; +using namespace TNL::Benchmarks; + +template< typename CellTopology, + int SpaceDimension = CellTopology::dimension, + typename... Params > +bool +setMeshParameters( Params&&... params ) +{ + bool status = MeshBenchmarksRunner< MinimalConfig, CellTopology, SpaceDimension, float, int, short int >::run( std::forward(params)... ) && + MeshBenchmarksRunner< FullConfig, CellTopology, SpaceDimension, float, int, short int >::run( std::forward(params)... ); + return status; +} + +bool +resolveCellTopology( Benchmark<> & benchmark, + const Config::ParameterContainer& parameters ) +{ + const String & meshFile = parameters.getParameter< String >( "mesh-file" ); + + auto reader = getMeshReader( meshFile, "auto" ); + + try { + reader->detectMesh(); + } + catch( const Meshes::Readers::MeshReaderError& e ) { + std::cerr << "Failed to detect mesh from file '" << meshFile << "'." << std::endl; + std::cerr << e.what() << std::endl; + return false; + } + + if( reader->getMeshType() != "Meshes::Mesh" ) { + std::cerr << "The mesh type " << reader->getMeshType() << " is not supported." << std::endl; + return false; + } + + using VTK::EntityShape; + switch( reader->getCellShape() ) + { + case EntityShape::Triangle: + return setMeshParameters< Topologies::Triangle >( benchmark, parameters ); + case EntityShape::Tetra: + return setMeshParameters< Topologies::Tetrahedron >( benchmark, parameters ); + case EntityShape::Polygon: + switch( reader->getSpaceDimension() ) + { + case 2: + return setMeshParameters< Topologies::Polygon, 2 >( benchmark, parameters ); + case 3: + return setMeshParameters< Topologies::Polygon, 3 >( benchmark, parameters ); + default: + std::cerr << "unsupported dimension for polygon mesh: " << reader->getSpaceDimension() << std::endl; + return false; + } + case EntityShape::Polyhedron: + return setMeshParameters< Topologies::Polyhedron >( benchmark, parameters ); + default: + std::cerr << "unsupported cell topology: " << getShapeName( reader->getCellShape() ) << std::endl; + return false; + } +} + +void +setupConfig( Config::ConfigDescription& config ) +{ + config.addDelimiter( "Benchmark settings:" ); + config.addEntry< String >( "log-file", "Log file name.", "tnl-benchmark-mesh.log"); + config.addEntry< String >( "output-mode", "Mode for opening the log file.", "overwrite" ); + config.addEntryEnum( "append" ); + config.addEntryEnum( "overwrite" ); + config.addEntry< int >( "loops", "Number of iterations for every computation.", 10 ); + config.addEntry< int >( "verbose", "Verbose mode.", 1 ); + config.addEntry< size_t >( "mem-limit", "Memory limit in MiB for mesh memory measurement.", 8000 ); + config.addRequiredEntry< String >( "mesh-file", "Path of the mesh to load for the benchmark." ); + config.addEntry< String >( "devices", "Run benchmarks on these devices.", "all" ); + config.addEntryEnum( "all" ); + config.addEntryEnum( "host" ); + #ifdef HAVE_CUDA + config.addEntryEnum( "cuda" ); + #endif + + config.addDelimiter( "Device settings:" ); + Devices::Host::configSetup( config ); + Devices::Cuda::configSetup( config ); +} + +int +main( int argc, char* argv[] ) +{ + Config::ParameterContainer parameters; + Config::ConfigDescription conf_desc; + + setupConfig( conf_desc ); + + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) + return 1; + + Devices::Host::setup( parameters ); + Devices::Cuda::setup( parameters ); + + const String & logFileName = parameters.getParameter< String >( "log-file" ); + const String & outputMode = parameters.getParameter< String >( "output-mode" ); + const int loops = parameters.getParameter< int >( "loops" ); + const int verbose = parameters.getParameter< int >( "verbose" ); + + // open log file + auto mode = std::ios::out; + if( outputMode == "append" ) + mode |= std::ios::app; + std::ofstream logFile( logFileName.getString(), mode ); + + // init benchmark and common metadata + Benchmark<> benchmark( logFile, loops, verbose ); + + // write global metadata into a separate file + std::map< std::string, std::string > metadata = getHardwareMetadata(); + writeMapAsJson( metadata, logFileName, ".metadata.json" ); + + if( ! resolveCellTopology( benchmark, parameters ) ) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} diff --git a/src/TNL/Algorithms/sort.h b/src/TNL/Algorithms/sort.h index 131561760e3c655f4fd690187948d96e69297ea3..e5df3b276987930bad1a45f75f06ab4f385f268a 100644 --- a/src/TNL/Algorithms/sort.h +++ b/src/TNL/Algorithms/sort.h @@ -117,7 +117,7 @@ void sort( Array& array, const Compare& compare, const Sorter& sorter = Sorter{} * ``` * auto compare = [=] __cuda_callable__ ( const Index& a , const Index& b ) -> bool { return .... }; * ``` - * \tparam Swap is a lambda function for swaping of two elements which are ordered wrong way. Both elements are represented by indeces as well. It supposed to + * \tparam Swap is a lambda function for swaping of two elements which are ordered wrong way. Both elements are represented by indices as well. It supposed to * be defined as: * ``` * auto swap = [=] __cuda_callable__ ( const Index& a , const Index& b ) mutable { swap( ....); }; diff --git a/src/TNL/Assert.h b/src/TNL/Assert.h index 99f833d24ee251c18e6c6bea16863a8b4dc0a829..6bb28c9d0bf3fc4aa950656d3ae23ffd58690d05 100644 --- a/src/TNL/Assert.h +++ b/src/TNL/Assert.h @@ -240,6 +240,18 @@ struct Formatter< bool > } }; +template< typename T, typename U > +struct Formatter< std::pair< T, U > > +{ + static std::string + printToString( const std::pair< T, U >& pair ) + { + ::std::stringstream ss; + ss << '(' << pair.first << ',' << pair.second << ')'; + return ss.str(); + } +}; + template< typename T1, typename T2 > __cuda_callable__ void cmpHelperOpFailure( const char* assertion, diff --git a/src/TNL/Containers/UnorderedIndexedSet.h b/src/TNL/Containers/UnorderedIndexedSet.h index 042a555bc1b7f54b88961dd1da4dbade48694aa2..839cf7baad845b505c871d46d6e41abeffcddead 100644 --- a/src/TNL/Containers/UnorderedIndexedSet.h +++ b/src/TNL/Containers/UnorderedIndexedSet.h @@ -32,24 +32,38 @@ public: using index_type = Index; using value_type = typename map_type::value_type; using size_type = typename map_type::size_type; + using iterator = typename map_type::iterator; + using const_iterator = typename map_type::const_iterator; using hasher = Hash; using key_equal = KeyEqual; - + void clear(); size_type size() const; Index insert( const Key& key ); + Index insert( Key&& key ); + std::pair< Index, bool > try_insert( const Key& key ); bool find( const Key& key, Index& index ) const; + void reserve( size_type count ); + size_type count( const Key& key ) const; size_type erase( const Key& key ); void print( std::ostream& str ) const; + + iterator begin(); + + const_iterator begin() const; + + iterator end(); + + const_iterator end() const; }; template< typename Element, diff --git a/src/TNL/Containers/UnorderedIndexedSet.hpp b/src/TNL/Containers/UnorderedIndexedSet.hpp index 4402ab55cca466c2c31f5c9f4704d94c33873395..f48e055f49290279dbeff1e62c65734f08e210c4 100644 --- a/src/TNL/Containers/UnorderedIndexedSet.hpp +++ b/src/TNL/Containers/UnorderedIndexedSet.hpp @@ -49,6 +49,18 @@ UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::insert( const Key& return iter->second; } +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +Index +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::insert( Key&& key ) +{ + auto iter = map.insert( value_type( std::move( key ), size() ) ).first; + return iter->second; +} + template< class Key, class Index, class Hash, @@ -72,10 +84,21 @@ UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::find( const Key& k auto iter = map.find( Key( key ) ); if( iter == map.end() ) return false; - index = iter->second.index; + index = iter->second; return true; } +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +void +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::reserve( size_type count ) +{ + map.reserve( count ); +} + template< class Key, class Index, class Hash, @@ -115,6 +138,50 @@ void UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::print( std::o } } +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +typename UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::iterator +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::begin() +{ + return map.begin(); +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +typename UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::const_iterator +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::begin() const +{ + return map.begin(); +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +typename UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::iterator +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::end() +{ + return map.end(); +} + +template< class Key, + class Index, + class Hash, + class KeyEqual, + class Allocator > +typename UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::const_iterator +UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::end() const +{ + return map.end(); +} + template< class Key, class Index, class Hash, diff --git a/src/TNL/Meshes/EntityShapeGroup.h b/src/TNL/Meshes/EntityShapeGroup.h new file mode 100644 index 0000000000000000000000000000000000000000..f9938068dc08d87cccfb2c5903eae278f8b4652b --- /dev/null +++ b/src/TNL/Meshes/EntityShapeGroup.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +namespace TNL { +namespace Meshes { +namespace VTK { + +template < EntityShape GeneralShape > +struct EntityShapeGroup +{ +}; + +template < EntityShape GeneralShape, int index > +struct EntityShapeGroupElement +{ +}; + +template <> +struct EntityShapeGroup< EntityShape::Polygon > +{ + static constexpr int size = 2; +}; + +template <> +struct EntityShapeGroupElement< EntityShape::Polygon, 0 > +{ + static constexpr EntityShape shape = EntityShape::Triangle; +}; + +template <> +struct EntityShapeGroupElement< EntityShape::Polygon, 1 > +{ + static constexpr EntityShape shape = EntityShape::Quad; +}; + +} // namespace VTK +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/EntityShapeGroupChecker.h b/src/TNL/Meshes/EntityShapeGroupChecker.h new file mode 100644 index 0000000000000000000000000000000000000000..35b0c5449a361574e35687752c3222a39915b2e8 --- /dev/null +++ b/src/TNL/Meshes/EntityShapeGroupChecker.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +namespace TNL { +namespace Meshes { +namespace VTK { + +template< EntityShape GeneralShape_ > +class EntityShapeGroupChecker +{ +public: + static constexpr EntityShape GeneralShape = GeneralShape_; + + static bool belong( EntityShape shape ) + { + if( GeneralShape == shape ) + { + return true; + } + else + { + bool result = false; + + Algorithms::staticFor< int, 0, EntityShapeGroup< GeneralShape >::size >( + [&] ( auto index ) { + EntityShape groupShape = EntityShapeGroupElement< GeneralShape, index >::shape; + result = result || ( shape == groupShape ); + } + ); + + return result; + } + } + + static bool bothBelong( EntityShape shape1, EntityShape shape2 ) + { + return belong( shape1 ) && belong( shape2 ); + } +}; + +} // namespace VTK +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Geometry/EntityDecomposer.h b/src/TNL/Meshes/Geometry/EntityDecomposer.h new file mode 100644 index 0000000000000000000000000000000000000000..268be58af1e595e68fc5c6af56a6381bc2362825 --- /dev/null +++ b/src/TNL/Meshes/Geometry/EntityDecomposer.h @@ -0,0 +1,227 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace TNL { +namespace Meshes { + +enum class EntityDecomposerVersion +{ + ConnectEdgesToCentroid, ConnectEdgesToPoint +}; + +template< typename MeshConfig, + typename Topology, + EntityDecomposerVersion EntityDecomposerVersion_ = EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion SubentityDecomposerVersion = EntityDecomposerVersion::ConnectEdgesToCentroid > +struct EntityDecomposer; + +// Polygon +template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersion > // SubentityDecomposerVersion is not used for polygons +struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion::ConnectEdgesToCentroid, SubentityDecomposerVersion > +{ + using Device = Devices::Host; + using Topology = Topologies::Polygon; + using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; + using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + + static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType& entity ) + { + const auto pointsCount = entity.template getSubentitiesCount< 0 >(); + if( pointsCount == 3 ) // polygon is triangle + return { 0, 1 }; // No extra points and no decomposition + return { 1, pointsCount }; // 1 extra centroid point and decomposition creates pointsCount triangles + } + + template< typename AddPointFunctor, + typename AddCellFunctor > + static void decompose( const MeshEntityType& entity, + AddPointFunctor&& addPoint, + AddCellFunctor&& addCell ) + { + const auto verticesCount = entity.template getSubentitiesCount< 0 >(); + if( verticesCount == 3 ) { // polygon is only copied as it's already a triangle + const auto v0 = entity.template getSubentityIndex< 0 >( 0 ); + const auto v1 = entity.template getSubentityIndex< 0 >( 1 ); + const auto v2 = entity.template getSubentityIndex< 0 >( 2 ); + addCell( v0, v1, v2 ); + } + else { // polygon is decomposed as it has got more than 3 vertices + const auto v0 = addPoint( getEntityCenter( entity.getMesh(), entity ) ); + // decompose polygon into triangles by connecting each edge to the centroid + for( LocalIndexType j = 0, k = 1; k < verticesCount; j++, k++ ) { + const auto v1 = entity.template getSubentityIndex< 0 >( j ); + const auto v2 = entity.template getSubentityIndex< 0 >( k ); + addCell( v0, v1, v2 ); + } + { // wrap around term + const auto v1 = entity.template getSubentityIndex< 0 >( verticesCount - 1 ); + const auto v2 = entity.template getSubentityIndex< 0 >( 0 ); + addCell( v0, v1, v2 ); + } + } + } +}; + +template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersion > // SubentityDecomposerVersion is not used for polygons +struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion::ConnectEdgesToPoint, SubentityDecomposerVersion > +{ + using Device = Devices::Host; + using Topology = Topologies::Polygon; + using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; + using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + + static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType& entity ) + { + const auto pointsCount = entity.template getSubentitiesCount< 0 >(); + return { 0, pointsCount - 2 }; // no extra points and there is a triangle for every non-adjacent edge to the 0th point (pointsCount - 2) + } + + template< typename AddPointFunctor, + typename AddCellFunctor > + static void decompose( const MeshEntityType& entity, + AddPointFunctor&& addPoint, + AddCellFunctor&& addCell ) + { + // decompose polygon into triangles by connecting 0th point to each non-adjacent edge + const auto verticesCount = entity.template getSubentitiesCount< 0 >(); + const auto v0 = entity.template getSubentityIndex< 0 >( 0 ); + for( LocalIndexType j = 1, k = 2; k < verticesCount; j++, k++ ) { + const auto v1 = entity.template getSubentityIndex< 0 >( j ); + const auto v2 = entity.template getSubentityIndex< 0 >( k ); + addCell( v0, v1, v2 ); + } + } +}; + +// Polyhedron +template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersion > +struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVersion::ConnectEdgesToCentroid, SubentityDecomposerVersion > +{ + using Device = Devices::Host; + using CellTopology = Topologies::Polyhedron; + using FaceTopology = Topologies::Polygon; + using MeshEntityType = MeshEntity< MeshConfig, Device, CellTopology >; + using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + using SubentityDecomposer = EntityDecomposer< MeshConfig, FaceTopology, SubentityDecomposerVersion >; + + static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType& entity ) + { + const auto& mesh = entity.getMesh(); + GlobalIndexType extraPointsCount = 1, // there is one new centroid point + entitiesCount = 0; + const auto facesCount = entity.template getSubentitiesCount< 2 >(); + for( LocalIndexType i = 0; i < facesCount; i++ ) { + const auto face = mesh.template getEntity< 2 >( entity.template getSubentityIndex< 2 >( i ) ); + + GlobalIndexType faceExtraPoints, faceEntitiesCount; + std::tie( faceExtraPoints, faceEntitiesCount ) = SubentityDecomposer::getExtraPointsAndEntitiesCount( face ); + extraPointsCount += faceExtraPoints; // add extra points from decomposition of faces + entitiesCount += faceEntitiesCount; // there is a new tetrahedron per triangle of a face + } + return { extraPointsCount, entitiesCount }; + } + + template< typename AddPointFunctor, + typename AddCellFunctor > + static void decompose( const MeshEntityType & entity, + AddPointFunctor&& addPoint, + AddCellFunctor&& addCell ) + { + const auto& mesh = entity.getMesh(); + const auto v3 = addPoint( getEntityCenter( mesh, entity ) ); + + // Lambda for creating tetrahedron from decomposed triangles of faces + auto addFace = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { + addCell( v0, v1, v2, v3 ); + }; + + const auto facesCount = entity.template getSubentitiesCount< 2 >(); + for( LocalIndexType i = 0; i < facesCount; i++ ) { + const auto face = mesh.template getEntity< 2 >( entity.template getSubentityIndex< 2 >( i ) ); + SubentityDecomposer::decompose( face, std::forward< AddPointFunctor >( addPoint ), addFace ); + } + } +}; + +template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersion > +struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVersion::ConnectEdgesToPoint, SubentityDecomposerVersion > +{ + // https://mathoverflow.net/a/7672 + using Device = Devices::Host; + using CellTopology = Topologies::Polyhedron; + using FaceTopology = Topologies::Polygon; + using MeshEntityType = MeshEntity< MeshConfig, Device, CellTopology >; + using MeshSubentityType = MeshEntity< MeshConfig, Device, FaceTopology >; + using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + using SubentityDecomposer = EntityDecomposer< MeshConfig, FaceTopology, SubentityDecomposerVersion >; + + static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType& entity ) + { + const auto& mesh = entity.getMesh(); + const auto v3 = entity.template getSubentityIndex< 0 >( 0 ); + GlobalIndexType extraPointsCount = 0, + entitiesCount = 0; + const auto facesCount = entity.template getSubentitiesCount< 2 >(); + for( LocalIndexType i = 0; i < facesCount; i++ ) { + const auto face = mesh.template getEntity< 2 >( entity.template getSubentityIndex< 2 >( i ) ); + if( !faceContainsPoint( face, v3 ) ) { // include only faces, that don't contain point v3 + GlobalIndexType faceExtraPoints, faceEntitiesCount; + std::tie( faceExtraPoints, faceEntitiesCount ) = SubentityDecomposer::getExtraPointsAndEntitiesCount( face ); + extraPointsCount += faceExtraPoints; // add extra points from decomposition of faces + entitiesCount += faceEntitiesCount; // there is a new tetrahedron per triangle of a face + } + } + return { extraPointsCount, entitiesCount }; + } + + template< typename AddPointFunctor, + typename AddCellFunctor > + static void decompose( const MeshEntityType& entity, + AddPointFunctor&& addPoint, + AddCellFunctor&& addCell ) + { + const auto& mesh = entity.getMesh(); + const auto v3 = entity.template getSubentityIndex< 0 >( 0 ); + + // Lambda for creating tetrahedron by connecting decomposed triangles of faces to 0th point of polyhedron + auto addFace = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { + addCell( v0, v1, v2, v3 ); + }; + + const auto facesCount = entity.template getSubentitiesCount< 2 >(); + for( LocalIndexType i = 0; i < facesCount; i++ ) { + const auto face = mesh.template getEntity< 2 >( entity.template getSubentityIndex< 2 >( i ) ); + if( !faceContainsPoint( face, v3 ) ) { // include only faces, that don't contain point v3 + SubentityDecomposer::decompose( face, std::forward< AddPointFunctor >( addPoint ), addFace ); + } + } + } + +private: + static bool faceContainsPoint( const MeshSubentityType& face, const GlobalIndexType point ) + { + const LocalIndexType pointsCount = face.template getSubentitiesCount< 0 >(); + for( LocalIndexType i = 0; i < pointsCount; i++ ) { + const auto facePoint = face.template getSubentityIndex< 0 >( i ); + if( point == facePoint ) + return true; + } + return false; + } +}; + +} // namespace Meshes +} // namespace TNL diff --git a/src/TNL/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h new file mode 100644 index 0000000000000000000000000000000000000000..d99d9ba8b153043a5e9f991702b2e8bdf83a361b --- /dev/null +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -0,0 +1,221 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace TNL { +namespace Meshes { + +// Polygon Mesh +template< typename ParentConfig > +struct TriangleConfig: public ParentConfig +{ + using CellTopology = Topologies::Triangle; +}; + +template< EntityDecomposerVersion DecomposerVersion, + EntityDecomposerVersion SubdecomposerVersion = EntityDecomposerVersion::ConnectEdgesToPoint, + typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true > +auto // returns MeshBuilder +decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) +{ + using namespace TNL; + using namespace TNL::Containers; + using namespace TNL::Algorithms; + + using TriangleMeshConfig = TriangleConfig< MeshConfig >; + using TriangleMesh = Mesh< TriangleMeshConfig, Devices::Host >; + using MeshBuilder = MeshBuilder< TriangleMesh >; + using GlobalIndexType = typename TriangleMesh::GlobalIndexType; + using PointType = typename TriangleMesh::PointType; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, DecomposerVersion >; + constexpr int CellDimension = TriangleMesh::getMeshDimension(); + + MeshBuilder meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< CellDimension >(); + + // Find the number of output points and cells as well as + // starting indices at which every cell will start writing new decomposed points and cells + using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; + Array< IndexPair, Devices::Host > indices( inCellsCount + 1 ); + auto setCounts = [&] ( GlobalIndexType i ) { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + indices[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCounts ); + indices[ inCellsCount ] = { 0, 0 }; // extend exclusive prefix sum by one element to also get result of reduce at the same time + auto reduction = [] ( const IndexPair& a, const IndexPair& b ) -> IndexPair { + return { a.first + b.first, a.second + b.second }; + }; + inplaceExclusiveScan( indices, 0, indices.getSize(), reduction, std::make_pair( 0, 0 ) ); + const auto& reduceResult = indices[ inCellsCount ]; + const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; + const GlobalIndexType outCellsCount = reduceResult.second; + meshBuilder.setEntitiesCount( outPointsCount, outCellsCount ); + + // Copy the points from inMesh to outMesh + auto copyPoint = [&] ( GlobalIndexType i ) mutable { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inPointsCount, copyPoint ); + + // Decompose each cell + auto decomposeCell = [&] ( GlobalIndexType i ) mutable { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + const auto& indexPair = indices[ i ]; + + // Lambda for adding new points + GlobalIndexType setPointIndex = inPointsCount + indexPair.first; + auto addPoint = [&] ( const PointType& point ) { + const auto pointIdx = setPointIndex++; + meshBuilder.setPoint( pointIdx, point ); + return pointIdx; + }; + + // Lambda for adding new cells + GlobalIndexType setCellIndex = indexPair.second; + auto addCell = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { + auto entitySeed = meshBuilder.getCellSeed( setCellIndex++ ); + entitySeed.setCornerId( 0, v0 ); + entitySeed.setCornerId( 1, v1 ); + entitySeed.setCornerId( 2, v2 ); + }; + + EntityDecomposer::decompose( cell, addPoint, addCell ); + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, decomposeCell ); + + return meshBuilder; +} + +template< EntityDecomposerVersion DecomposerVersion, + EntityDecomposerVersion SubdecomposerVersion = EntityDecomposerVersion::ConnectEdgesToPoint, + typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true > +auto // returns Mesh +getDecomposedMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) +{ + using TriangleMeshConfig = TriangleConfig< MeshConfig >; + using TriangleMesh = Mesh< TriangleMeshConfig, Devices::Host >; + + TriangleMesh outMesh; + auto meshBuilder = decomposeMesh< DecomposerVersion >( inMesh ); + meshBuilder.build( outMesh ); + return outMesh; +} + +// Polyhedral Mesh +template< typename ParentConfig > +struct TetrahedronConfig: public ParentConfig +{ + using CellTopology = Topologies::Tetrahedron; +}; + +template< EntityDecomposerVersion DecomposerVersion, + EntityDecomposerVersion SubdecomposerVersion, + typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > +auto // returns MeshBuilder +decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) +{ + using namespace TNL; + using namespace TNL::Containers; + using namespace TNL::Algorithms; + + using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; + using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; + using MeshBuilder = MeshBuilder< TetrahedronMesh >; + using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; + using PointType = typename TetrahedronMesh::PointType; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polyhedron, DecomposerVersion, SubdecomposerVersion >; + constexpr int CellDimension = TetrahedronMesh::getMeshDimension(); + + MeshBuilder meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< CellDimension >(); + + // Find the number of output points and cells as well as + // starting indices at which every cell will start writing new decomposed points and cells + using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; + Array< IndexPair, Devices::Host > indices( inCellsCount + 1 ); + auto setCounts = [&] ( GlobalIndexType i ) { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + indices[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCounts ); + indices[ inCellsCount ] = { 0, 0 }; // extend exclusive prefix sum by one element to also get result of reduce at the same time + auto reduction = [] ( const IndexPair& a, const IndexPair& b ) -> IndexPair { + return { a.first + b.first, a.second + b.second }; + }; + inplaceExclusiveScan( indices, 0, indices.getSize(), reduction, std::make_pair( 0, 0 ) ); + const auto& reduceResult = indices[ inCellsCount ]; + const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; + const GlobalIndexType outCellsCount = reduceResult.second; + meshBuilder.setEntitiesCount( outPointsCount, outCellsCount ); + + // Copy the points from inMesh to outMesh + auto copyPoint = [&] ( GlobalIndexType i ) mutable { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inPointsCount, copyPoint ); + + // Decompose each cell + auto decomposeCell = [&] ( GlobalIndexType i ) mutable { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + const auto& indexPair = indices[ i ]; + + // Lambda for adding new points + GlobalIndexType setPointIndex = inPointsCount + indexPair.first; + auto addPoint = [&] ( const PointType& point ) { + const auto pointIdx = setPointIndex++; + meshBuilder.setPoint( pointIdx, point ); + return pointIdx; + }; + + // Lambda for adding new cells + GlobalIndexType setCellIndex = indexPair.second; + auto addCell = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2, GlobalIndexType v3 ) { + auto entitySeed = meshBuilder.getCellSeed( setCellIndex++ ); + entitySeed.setCornerId( 0, v0 ); + entitySeed.setCornerId( 1, v1 ); + entitySeed.setCornerId( 2, v2 ); + entitySeed.setCornerId( 3, v3 ); + }; + + EntityDecomposer::decompose( cell, addPoint, addCell ); + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, decomposeCell ); + + return meshBuilder; +} + +template< EntityDecomposerVersion DecomposerVersion, + EntityDecomposerVersion SubDecomposerVersion, + typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > +auto // returns Mesh +getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; + using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; + + TetrahedronMesh outMesh; + auto meshBuilder = decomposeMesh< DecomposerVersion, SubDecomposerVersion >( inMesh ); + meshBuilder.build( outMesh ); + return outMesh; +} + +} // namespace Meshes +} // namespace TNL diff --git a/src/TNL/Meshes/Geometry/getEntityCenter.h b/src/TNL/Meshes/Geometry/getEntityCenter.h index addef6b9f3d01839d81bfeb64c8cf948405d8942..031bd62e8d916da283e0d9d6d6f13a35da461b13 100644 --- a/src/TNL/Meshes/Geometry/getEntityCenter.h +++ b/src/TNL/Meshes/Geometry/getEntityCenter.h @@ -50,7 +50,7 @@ getEntityCenter( const Mesh< MeshConfig, Device > & mesh, const MeshEntity< MeshConfig, Device, EntityTopology > & entity ) { using EntityType = MeshEntity< MeshConfig, Device, EntityTopology >; - constexpr typename MeshConfig::LocalIndexType subvertices = EntityType::template SubentityTraits< 0 >::count; + const typename MeshConfig::LocalIndexType subvertices = entity.template getSubentitiesCount< 0 >(); typename MeshTraits< MeshConfig >::PointType c = 0; for( typename MeshConfig::LocalIndexType i = 0; i < subvertices; diff --git a/src/TNL/Meshes/Geometry/getEntityMeasure.h b/src/TNL/Meshes/Geometry/getEntityMeasure.h index fb1e2d468b097b9a292d5d901bdbe2f32630e565..79fd31680045e79c8709fcdb01d707f05b921b64 100644 --- a/src/TNL/Meshes/Geometry/getEntityMeasure.h +++ b/src/TNL/Meshes/Geometry/getEntityMeasure.h @@ -14,12 +14,17 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include +#include +#include namespace TNL { namespace Meshes { @@ -172,5 +177,234 @@ getEntityMeasure( const Mesh< MeshConfig, Device > & mesh, + getTetrahedronVolume( v6 - v4, v2 - v4, v7 - v4 ); } +// Polygon +template< int Coord1, + int Coord2, + typename MeshConfig, + typename Device > +__cuda_callable__ +typename MeshConfig::RealType +getPolygon2DArea( const Mesh< MeshConfig, Device > & mesh, + const MeshEntity< MeshConfig, Device, Topologies::Polygon > & entity ) +{ + // http://geomalgorithms.com/code.html (function area2D_Polygon) + + static_assert( Coord1 >= 0 && Coord1 <= 2 && + Coord2 >= 0 && Coord2 <= 2 && + Coord1 != Coord2, "Coord1 and Coord2 must be different integers with possible values {0, 1, 2}." ); + + using Real = typename MeshConfig::RealType; + using Index = typename MeshConfig::LocalIndexType; + + Real area{ 0.0 }; + const auto n = entity.template getSubentitiesCount< 0 >(); + for ( Index i = 1, j = 2, k = 0; j < n; i++, j++, k++ ) { + const auto& v0 = mesh.getPoint( entity.template getSubentityIndex< 0 >( i ) ); + const auto& v1 = mesh.getPoint( entity.template getSubentityIndex< 0 >( j ) ); + const auto& v2 = mesh.getPoint( entity.template getSubentityIndex< 0 >( k ) ); + area += v0[Coord1] * ( v1[Coord2] - v2[Coord2] ); + } + + // 1. wrap around term + { + const auto& v0 = mesh.getPoint( entity.template getSubentityIndex< 0 >( n - 1 ) ); + const auto& v1 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 0 ) ); + const auto& v2 = mesh.getPoint( entity.template getSubentityIndex< 0 >( n - 2 ) ); + area += v0[Coord1] * ( v1[Coord2] - v2[Coord2] ); + } + + // 2. wrap around term + { + const auto& v0 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 0 ) ); + const auto& v1 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 1 ) ); + const auto& v2 = mesh.getPoint( entity.template getSubentityIndex< 0 >( n - 1 ) ); + area += v0[Coord1] * ( v1[Coord2] - v2[Coord2] ); + } + + return Real( 0.5 ) * area; +} + +template< typename MeshConfig, + typename Device, + std::enable_if_t< MeshConfig::spaceDimension == 2, bool > = true > +__cuda_callable__ +typename MeshConfig::RealType +getEntityMeasure( const Mesh< MeshConfig, Device > & mesh, + const MeshEntity< MeshConfig, Device, Topologies::Polygon > & entity ) +{ + const auto area = getPolygon2DArea< 0, 1 >( mesh, entity ); + return TNL::abs( area ); +} + +template< typename MeshConfig, + typename Device, + std::enable_if_t< MeshConfig::spaceDimension == 3, bool > = true > +__cuda_callable__ +typename MeshConfig::RealType +getEntityMeasure( const Mesh< MeshConfig, Device > & mesh, + const MeshEntity< MeshConfig, Device, Topologies::Polygon > & entity ) + +{ + // http://geomalgorithms.com/code.html (function area3D_Polygon) + + using Real = typename MeshConfig::RealType; + + // select largest abs coordinate of normal vector to ignore for projection + auto normal = getNormalVector( mesh, entity ); + normal = TNL::abs( normal ); + int coord = 2; // ignore z-coord + if ( normal.x() > normal.y() ) { + if ( normal.x() > normal.z() ) coord = 0; // ignore x-coord + } + else if ( normal.y() > normal.z() ) coord = 1; // ignore y-coord + + Real area; + switch( coord ) { + case 0: // ignored x-coord + area = getPolygon2DArea< 1, 2 >( mesh, entity ); + area *= l2Norm( normal ) / normal.x(); + break; + case 1: // ignored y-coord + area = getPolygon2DArea< 0, 2 >( mesh, entity ); + area *= l2Norm( normal ) / normal.y(); + break; + default: // ignored z-coord + area = getPolygon2DArea< 0, 1 >( mesh, entity ); + area *= l2Norm( normal ) / normal.z(); + break; + } + return TNL::abs( area ); +} + +// Wedge +template< typename MeshConfig, + typename Device > +__cuda_callable__ +typename MeshConfig::RealType +getEntityMeasure( const Mesh< MeshConfig, Device > & mesh, + const MeshEntity< MeshConfig, Device, Topologies::Wedge > & entity ) +{ + using Real = typename MeshConfig::RealType; + + const auto& v0 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 0 ) ); + const auto& v1 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 1 ) ); + const auto& v2 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 2 ) ); + const auto& v3 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 3 ) ); + const auto& v4 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 4 ) ); + const auto& v5 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 5 ) ); + // Partition wedge into three tetrahedrons. + return getTetrahedronVolume( v2 - v3, v0 - v3, v1 - v3 ) + + getTetrahedronVolume( v2 - v3, v1 - v3, v4 - v3 ) + + getTetrahedronVolume( v2 - v3, v4 - v3, v5 - v3 ); +} + +// Pyramid +template< typename MeshConfig, + typename Device > +__cuda_callable__ +typename MeshConfig::RealType +getEntityMeasure( const Mesh< MeshConfig, Device > & mesh, + const MeshEntity< MeshConfig, Device, Topologies::Pyramid > & entity ) +{ + using Real = typename MeshConfig::RealType; + + const auto& v0 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 0 ) ); + const auto& v1 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 1 ) ); + const auto& v2 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 2 ) ); + const auto& v3 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 3 ) ); + const auto& v4 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 4 ) ); + // Partition pyramid into two tetrahedrons. + return getTetrahedronVolume( v4 - v0, v3 - v0, v1 - v0 ) + + getTetrahedronVolume( v4 - v2, v1 - v2, v3 - v2 ); +} + +// Polyhedron +/*template< typename MeshConfig, + typename Device > +__cuda_callable__ +typename MeshConfig::RealType +getEntityMeasure( const Mesh< MeshConfig, Device > & mesh, + const MeshEntity< MeshConfig, Device, Topologies::Polyhedron > & entity ) +{ + using Real = typename MeshConfig::RealType; + using Index = typename MeshConfig::LocalIndexType; + Real volume{ 0.0 }; + const Index facesCount = entity.template getSubentitiesCount< 2 >(); + for( Index faceIdx = 0; faceIdx < facesCount; faceIdx++ ) { + const auto face = mesh.template getEntity< 2 >( entity.template getSubentityIndex< 2 >( faceIdx ) ); + const Index verticesCount = face.template getSubentitiesCount< 0 >(); + const auto& v0 = mesh.getPoint( face.template getSubentityIndex< 0 >( 0 ) ); + for( Index i = 1, j = 2; j < verticesCount; i++, j++ ) { + const auto& v1 = mesh.getPoint( face.template getSubentityIndex< 0 >( i ) ); + const auto& v2 = mesh.getPoint( face.template getSubentityIndex< 0 >( j ) ); + // Partition polyhedron into tetrahedrons by triangulating faces and connecting each triangle to the origin point (0,0,0). + // It is required that vertices of all faces are stored consistently in CW or CCW order as faces are viewed from the outside. + // Otherwise signs of some tetrahedron volumes may be incorrect, resulting in overall incorrect volume. + // https://stackoverflow.com/a/1849746 + + // volume += dot(v0 x v1, v2) + volume += Real { + ( v0.y() * v1.z() - v0.z() * v1.y() ) * v2.x() + + ( v0.z() * v1.x() - v0.x() * v1.z() ) * v2.y() + + ( v0.x() * v1.y() - v0.y() * v1.x() ) * v2.z() + }; + } + } + return Real{ 1.0 / 6.0 } * TNL::abs( volume ); +}*/ + +template< typename MeshConfig, + typename Device > +__cuda_callable__ +typename MeshConfig::RealType +getEntityMeasure( const Mesh< MeshConfig, Device > & mesh, + const MeshEntity< MeshConfig, Device, Topologies::Polyhedron > & entity ) +{ + using Real = typename MeshConfig::RealType; + using Index = typename MeshConfig::LocalIndexType; + Real volume{ 0.0 }; + const Index facesCount = entity.template getSubentitiesCount< 2 >(); + const auto& v3 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 0 ) ); + for( Index faceIdx = 0; faceIdx < facesCount; faceIdx++ ) { + const auto face = mesh.template getEntity< 2 >( entity.template getSubentityIndex< 2 >( faceIdx ) ); + const Index verticesCount = face.template getSubentitiesCount< 0 >(); + const auto& v0 = mesh.getPoint( face.template getSubentityIndex< 0 >( 0 ) ); + for( Index i = 1, j = 2; j < verticesCount; i++, j++ ) { + const auto& v1 = mesh.getPoint( face.template getSubentityIndex< 0 >( i ) ); + const auto& v2 = mesh.getPoint( face.template getSubentityIndex< 0 >( j ) ); + // Partition polyhedron into tetrahedrons by triangulating faces and connecting each triangle to one point of the polyhedron. + volume += getTetrahedronVolume( v3 - v0, v2 - v0, v1 - v0 ); + } + } + return volume; +} + +template< typename MeshConfig > +__cuda_callable__ +typename MeshConfig::RealType +getEntityMeasure( const Mesh< MeshConfig, Devices::Cuda > & mesh, + const MeshEntity< MeshConfig, Devices::Cuda, Topologies::Polyhedron > & entity ) +{ + using Real = typename MeshConfig::RealType; + using Index = typename MeshConfig::LocalIndexType; + using Point = typename Mesh< MeshConfig, Devices::Cuda >::PointType; + Real volume{ 0.0 }; + const Index facesCount = entity.template getSubentitiesCount< 2 >(); + const Point v3 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 0 ) ); + for( Index faceIdx = 0; faceIdx < facesCount; faceIdx++ ) { + const auto face = mesh.template getEntity< 2 >( entity.template getSubentityIndex< 2 >( faceIdx ) ); + const Index verticesCount = face.template getSubentitiesCount< 0 >(); + const Point v0 = mesh.getPoint( face.template getSubentityIndex< 0 >( 0 ) ); + Point v1 = mesh.getPoint( face.template getSubentityIndex< 0 >( 1 ) ); + for( Index j = 2; j < verticesCount; j++ ) { + const Point v2 = mesh.getPoint( face.template getSubentityIndex< 0 >( j ) ); + // Partition polyhedron into tetrahedrons by triangulating faces and connecting each triangle to one point of the polyhedron. + volume += getTetrahedronVolume( v3 - v0, v2 - v0, v1 - v0 ); + v1 = v2; + } + } + return volume; +} + } // namespace Meshes } // namespace TNL diff --git a/src/TNL/Meshes/Geometry/getOutwardNormalVector.h b/src/TNL/Meshes/Geometry/getOutwardNormalVector.h index 6221236f5942f4d274f4918f2246ce8b99462a62..c5b6a8243892586d8282d5ac1353495b9714af15 100644 --- a/src/TNL/Meshes/Geometry/getOutwardNormalVector.h +++ b/src/TNL/Meshes/Geometry/getOutwardNormalVector.h @@ -114,6 +114,27 @@ getOutwardNormalVector( const Mesh< MeshConfig, Device > & mesh, return - n / l2Norm( n ); } +template< typename MeshConfig, typename Device, typename EntityTopology > +__cuda_callable__ +typename MeshTraits< MeshConfig >::PointType +getNormalVector( const Mesh< MeshConfig, Device > & mesh, + const MeshEntity< MeshConfig, Device, EntityTopology > & entity ) +{ + using PointType = typename MeshTraits< MeshConfig >::PointType; + + const auto& v0 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 0 ) ); + const auto& v1 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 1 ) ); + const auto& v2 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 2 ) ); + const PointType u1 = v0 - v1; + const PointType u2 = v0 - v2; + const PointType n { + u1.y() * u2.z() - u1.z() * u2.y(), // first component of the cross product + u1.z() * u2.x() - u1.x() * u2.z(), // second component of the cross product + u1.x() * u2.y() - u1.y() * u2.x() // third component of the cross product + }; + return n; +} + template< typename MeshConfig, typename Device, typename EntityTopology > __cuda_callable__ typename MeshTraits< MeshConfig >::PointType @@ -127,16 +148,7 @@ getOutwardNormalVector( const Mesh< MeshConfig, Device > & mesh, static_assert( std::is_same< typename MeshType::Face, FaceType >::value, "getOutwardNormalVector called for an entity which is not a face" ); static_assert( MeshConfig::spaceDimension == 3, "general overload intended for 3D was called with the wrong space dimension" ); - const auto& v0 = mesh.getPoint( face.template getSubentityIndex< 0 >( 0 ) ); - const auto& v1 = mesh.getPoint( face.template getSubentityIndex< 0 >( 1 ) ); - const auto& v2 = mesh.getPoint( face.template getSubentityIndex< 0 >( 2 ) ); - const PointType u1 = v0 - v1; - const PointType u2 = v0 - v2; - const PointType n { - u1.y() * u2.z() - u1.z() * u2.y(), // first component of the cross product - u1.z() * u2.x() - u1.x() * u2.z(), // second component of the cross product - u1.x() * u2.y() - u1.y() * u2.x() // third component of the cross product - }; + const PointType n = getNormalVector( mesh, face ); // check on which side of the face is the reference cell center const PointType faceCenter = getEntityCenter( mesh, face ); diff --git a/src/TNL/Meshes/Geometry/getPlanarMesh.h b/src/TNL/Meshes/Geometry/getPlanarMesh.h new file mode 100644 index 0000000000000000000000000000000000000000..f32e5da9717cec565ae550e5b4f07debe919eeab --- /dev/null +++ b/src/TNL/Meshes/Geometry/getPlanarMesh.h @@ -0,0 +1,310 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace TNL { +namespace Meshes { + +// 3D Polygon Mesh +template< EntityDecomposerVersion DecomposerVersion, + typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true, + std::enable_if_t< MeshConfig::spaceDimension == 3, bool > = true > +auto // returns MeshBuilder +planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) +{ + using namespace TNL; + using namespace TNL::Containers; + using namespace TNL::Algorithms; + + using PolygonMesh = Mesh< MeshConfig, Devices::Host >; + using MeshBuilder = MeshBuilder< PolygonMesh >; + using NeighborCountsArray = typename MeshBuilder::NeighborCountsArray; + using GlobalIndexType = typename PolygonMesh::GlobalIndexType; + using LocalIndexType = typename PolygonMesh::LocalIndexType; + using PointType = typename PolygonMesh::PointType; + using RealType = typename PolygonMesh::RealType; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, DecomposerVersion >; + constexpr int CellDimension = PolygonMesh::getMeshDimension(); + + constexpr RealType precision{ 1e-6 }; + + MeshBuilder meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< CellDimension >(); + + // Find the number of output points and cells as well as + // starting indices at which every cell will start writing new points and cells + using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; + Array< IndexPair, Devices::Host > indices( inCellsCount + 1 ); + auto setCounts = [&] ( GlobalIndexType i ) { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + if( isPlanar( inMesh, cell, precision ) ) { + indices[ i ] = { 0, 1 }; // cell is not decomposed (0 extra points, 1 cell) + } + else { + indices[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + } + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCounts ); + indices[ inCellsCount ] = { 0, 0 }; // extend exclusive prefix sum by one element to also get result of reduce at the same time + auto reduction = [] ( const IndexPair& a, const IndexPair& b ) -> IndexPair { + return { a.first + b.first, a.second + b.second }; + }; + inplaceExclusiveScan( indices, 0, indices.getSize(), reduction, std::make_pair( 0, 0 ) ); + const auto& reduceResult = indices[ inCellsCount ]; + const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; + const GlobalIndexType outCellsCount = reduceResult.second; + meshBuilder.setEntitiesCount( outPointsCount, outCellsCount ); + + // Copy the points from inMesh to outMesh + auto copyPoint = [&] ( GlobalIndexType i ) mutable { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inPointsCount, copyPoint ); + + // set corner counts for cells + NeighborCountsArray cellCornersCounts( outCellsCount ); + auto setCornersCount = [&] ( GlobalIndexType i ) mutable { + GlobalIndexType cellIndex = indices[ i ].second; + const GlobalIndexType nextCellIndex = indices[ i + 1 ].second; + const GlobalIndexType cellsCount = nextCellIndex - cellIndex; + + if( cellsCount == 1 ) { // cell is already planar (cell is copied) + const auto cell = inMesh.template getEntity< CellDimension >( i ); + const auto verticesCount = cell.template getSubentitiesCount< 0 >(); + cellCornersCounts[ cellIndex ] = verticesCount; + } + else { // cell is not planar (cell is decomposed) + for( ; cellIndex < nextCellIndex; cellIndex++ ) { + cellCornersCounts[ cellIndex ] = 3; + } + } + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCornersCount ); + meshBuilder.setCellCornersCounts( std::move( cellCornersCounts ) ); + + // Decompose non-planar cells and copy the rest + auto decomposeCell = [&] ( GlobalIndexType i ) mutable { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + const auto& indexPair = indices[ i ]; + const auto& nextIndexPair = indices[ i + 1 ]; + const GlobalIndexType cellsCount = nextIndexPair.second - indexPair.second; + + if( cellsCount == 1 ) { // cell is already planar (cell is copied) + auto seed = meshBuilder.getCellSeed( indexPair.second ); + const auto verticesCount = cell.template getSubentitiesCount< 0 >(); + for( LocalIndexType j = 0; j < verticesCount; j++ ) { + seed.setCornerId( j, cell.template getSubentityIndex< 0 >( j ) ); + } + } + else { // cell is not planar (cell is decomposed) + // Lambda for adding new points + GlobalIndexType setPointIndex = inPointsCount + indexPair.first; + auto addPoint = [&] ( const PointType& point ) { + const auto pointIdx = setPointIndex++; + meshBuilder.setPoint( pointIdx, point ); + return pointIdx; + }; + + // Lambda for adding new cells + GlobalIndexType setCellIndex = indexPair.second; + auto addCell = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { + auto entitySeed = meshBuilder.getCellSeed( setCellIndex++ ); + entitySeed.setCornerId( 0, v0 ); + entitySeed.setCornerId( 1, v1 ); + entitySeed.setCornerId( 2, v2 ); + }; + + EntityDecomposer::decompose( cell, addPoint, addCell ); + } + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, decomposeCell ); + + return meshBuilder; +} + +// Polyhedral Mesh +template< EntityDecomposerVersion DecomposerVersion, + typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > +auto // returns MeshBuilder +planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) +{ + using namespace TNL; + using namespace TNL::Containers; + using namespace TNL::Algorithms; + + using PolyhedronMesh = Mesh< MeshConfig, Devices::Host >; + using MeshBuilder = MeshBuilder< PolyhedronMesh >; + using NeighborCountsArray = typename MeshBuilder::NeighborCountsArray; + using GlobalIndexType = typename PolyhedronMesh::GlobalIndexType; + using LocalIndexType = typename PolyhedronMesh::LocalIndexType; + using PointType = typename PolyhedronMesh::PointType; + using RealType = typename PolyhedronMesh::RealType; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, DecomposerVersion >; + constexpr int CellDimension = PolyhedronMesh::getMeshDimension(); + constexpr int FaceDimension = CellDimension - 1; + + constexpr RealType precision{ 1e-6 }; + + MeshBuilder meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inFacesCount = inMesh.template getEntitiesCount< FaceDimension >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< CellDimension >(); + + // Find the number of output points and faces as well as + // starting indices at which every face will start writing new points and faces + using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; + Array< IndexPair, Devices::Host > indices( inFacesCount + 1 ); + auto setCounts = [&] ( GlobalIndexType i ) { + const auto face = inMesh.template getEntity< FaceDimension >( i ); + if( isPlanar( inMesh, face, precision ) ) { + indices[ i ] = { 0, 1 }; // face is not decomposed (0 extra points, 1 face) + } + else { + indices[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( face ); + } + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inFacesCount, setCounts ); + indices[ inFacesCount ] = { 0, 0 }; // extend exclusive prefix sum by one element to also get result of reduce at the same time + auto reduction = [] ( const IndexPair& a, const IndexPair& b ) -> IndexPair { + return { a.first + b.first, a.second + b.second }; + }; + inplaceExclusiveScan( indices, 0, indices.getSize(), reduction, std::make_pair( 0, 0 ) ); + const auto& reduceResult = indices[ inFacesCount ]; + const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; + const GlobalIndexType outFacesCount = reduceResult.second; + const GlobalIndexType outCellsCount = inCellsCount; // The number of cells stays the same + meshBuilder.setEntitiesCount( outPointsCount, outCellsCount, outFacesCount ); + + // Copy the points from inMesh to outMesh + auto copyPoint = [&] ( GlobalIndexType i ) mutable { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inPointsCount, copyPoint ); + + // set corner counts for cells + NeighborCountsArray cellCornersCounts( outCellsCount ); + auto setCellCornersCount = [&] ( GlobalIndexType i ) mutable { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + const LocalIndexType cellFacesCount = cell.template getSubentitiesCount< FaceDimension >(); + + // Count the number of corner ids for the cell + LocalIndexType cornersCount = 0; + for( LocalIndexType j = 0; j < cellFacesCount; j++ ) { + const GlobalIndexType faceIdx = cell.template getSubentityIndex< FaceDimension >( j ); + cornersCount += indices[ faceIdx + 1 ].second - indices[ faceIdx ].second; + } + + cellCornersCounts[ i ] = cornersCount; + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCellCornersCount ); + meshBuilder.setCellCornersCounts( std::move( cellCornersCounts ) ); + + // Set corner ids for cells + auto setCellCornersIds = [&] ( GlobalIndexType i ) mutable { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + const LocalIndexType cellFacesCount = cell.template getSubentitiesCount< FaceDimension >(); + auto cellSeed = meshBuilder.getCellSeed( i ); + for( LocalIndexType j = 0, o = 0; j < cellFacesCount; j++ ) { + const GlobalIndexType faceIdx = cell.template getSubentityIndex< FaceDimension >( j ); + const GlobalIndexType endFaceIdx = indices[ faceIdx + 1 ].second; + for( GlobalIndexType k = indices[ faceIdx ].second; k < endFaceIdx; k++ ) { + cellSeed.setCornerId( o++, k ); + } + } + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCellCornersIds ); + + // set corner counts for faces + NeighborCountsArray faceCornersCounts( outFacesCount ); + auto setFaceCornersCount = [&] ( GlobalIndexType i ) mutable { + GlobalIndexType faceIndex = indices[ i ].second; + const GlobalIndexType nextFaceIndex = indices[ i + 1 ].second; + const GlobalIndexType facesCount = nextFaceIndex - faceIndex; + if( facesCount == 1 ) { // face is already planar (it is copied) + const auto face = inMesh.template getEntity< FaceDimension >( i ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + faceCornersCounts[ faceIndex ] = verticesCount; + } + else { // face is not planar (it is decomposed) + for( ; faceIndex < nextFaceIndex; faceIndex++ ) { + faceCornersCounts[ faceIndex ] = 3; + } + } + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inFacesCount, setFaceCornersCount ); + meshBuilder.setFaceCornersCounts( std::move( faceCornersCounts ) ); + + // Decompose non-planar faces and copy the rest + auto decomposeFace = [&] ( GlobalIndexType i ) mutable { + const auto face = inMesh.template getEntity< FaceDimension >( i ); + const auto& indexPair = indices[ i ]; + const auto& nextIndexPair = indices[ i + 1 ]; + const GlobalIndexType facesCount = nextIndexPair.second - indexPair.second; + + if( facesCount == 1 ) { // face is already planar (it is copied) + auto seed = meshBuilder.getFaceSeed( indexPair.second ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + for( LocalIndexType j = 0; j < verticesCount; j++ ) { + seed.setCornerId( j, face.template getSubentityIndex< 0 >( j ) ); + } + } + else { // face is not planar (it is decomposed) + // Lambda for adding new points + GlobalIndexType setPointIndex = inPointsCount + indexPair.first; + auto addPoint = [&] ( const PointType& point ) { + const auto pointIdx = setPointIndex++; + meshBuilder.setPoint( pointIdx, point ); + return pointIdx; + }; + + // Lambda for adding new faces + GlobalIndexType setFaceIndex = indexPair.second; + auto addFace = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { + auto entitySeed = meshBuilder.getFaceSeed( setFaceIndex++ ); + entitySeed.setCornerId( 0, v0 ); + entitySeed.setCornerId( 1, v1 ); + entitySeed.setCornerId( 2, v2 ); + }; + + EntityDecomposer::decompose( face, addPoint, addFace ); + } + }; + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inFacesCount, decomposeFace ); + + return meshBuilder; +} + +template< EntityDecomposerVersion DecomposerVersion, + typename MeshConfig, + std::enable_if_t< MeshConfig::spaceDimension == 3 && + ( std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value || + std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value ), + bool > = true > +auto // returns Mesh +getPlanarMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) +{ + using Mesh = Mesh< MeshConfig, Devices::Host >; + + Mesh outMesh; + auto meshBuilder = planarCorrection< DecomposerVersion >( inMesh ); + meshBuilder.build( outMesh ); + return outMesh; +} + +} // namespace Meshes +} // namespace TNL diff --git a/src/TNL/Meshes/Geometry/isPlanar.h b/src/TNL/Meshes/Geometry/isPlanar.h new file mode 100644 index 0000000000000000000000000000000000000000..8f50ee5a9907944cd4db23ce241636c3e35e0ae4 --- /dev/null +++ b/src/TNL/Meshes/Geometry/isPlanar.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace TNL { +namespace Meshes { + +// Polygon +template< typename MeshConfig, + typename Device, + std::enable_if_t< MeshConfig::spaceDimension == 3, bool > = true > +__cuda_callable__ +bool +isPlanar( const Mesh< MeshConfig, Device > & mesh, + const MeshEntity< MeshConfig, Device, Topologies::Polygon > & entity, + const typename MeshConfig::RealType precision ) +{ + using Real = typename MeshConfig::RealType; + using Index = typename MeshConfig::LocalIndexType; + const auto& v0 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 0 ) ); + const auto& v1 = mesh.getPoint( entity.template getSubentityIndex< 0 >( 1 ) ); + const Index verticesCount = entity.template getSubentitiesCount< 0 >(); + for( Index i = 2, j = 3; j < verticesCount; i++, j++ ) { + const auto& v2 = mesh.getPoint( entity.template getSubentityIndex< 0 >( i ) ); + const auto& v3 = mesh.getPoint( entity.template getSubentityIndex< 0 >( j ) ); + const Real volume{ getTetrahedronVolume( v0 - v1, v2 - v1, v3 - v1 ) }; + if( volume > precision ) + return false; + } + return true; +} + +} // namespace Meshes +} // namespace TNL diff --git a/src/TNL/Meshes/Mesh.h b/src/TNL/Meshes/Mesh.h index 506850eceaafc7f652b0ef77284c7f1eff4384a8..808830904d8989360a0b1f0665f42078f579ea27 100644 --- a/src/TNL/Meshes/Mesh.h +++ b/src/TNL/Meshes/Mesh.h @@ -50,7 +50,8 @@ class MeshInitializableBase // The points and cellSeeds arrays will be reset when not needed to save memory. void init( typename MeshTraitsType::PointArrayType& points, - typename MeshTraitsType::CellSeedArrayType& cellSeeds ); + typename MeshTraitsType::FaceSeedMatrixType& faceSeeds, + typename MeshTraitsType::CellSeedMatrixType& cellSeeds ); }; // The mesh cannot be initialized on CUDA GPU, so this specialization is empty. @@ -92,10 +93,14 @@ class Mesh Mesh( const Mesh& mesh ); + Mesh( Mesh&& mesh ) = default; + template< typename Device_ > Mesh( const Mesh< MeshConfig, Device_ >& mesh ); - Mesh& operator=( const Mesh& mesh ); + Mesh& operator=( const Mesh& mesh ) = default; + + Mesh& operator=( Mesh&& mesh ) = default; template< typename Device_ > Mesh& operator=( const Mesh< MeshConfig, Device_ >& mesh ); @@ -126,6 +131,9 @@ class Mesh __cuda_callable__ EntityType< Dimension > getEntity( const GlobalIndexType entityIndex ) const; + template< int Dimension > + void setEntitiesCount( const typename MeshTraitsType::GlobalIndexType& entitiesCount ); + // duplicated for compatibility with grids template< typename EntityType > __cuda_callable__ @@ -138,6 +146,10 @@ class Mesh /** * \brief Returns the spatial coordinates of the vertex with given index. */ + const typename MeshTraitsType::PointArrayType& getPoints() const; + + typename MeshTraitsType::PointArrayType& getPoints(); + __cuda_callable__ const PointType& getPoint( const GlobalIndexType vertexIndex ) const; @@ -268,14 +280,15 @@ class Mesh void writeProlog( Logger& logger ) const; protected: - // Methods for the mesh initializer - using StorageBaseType::getPoints; - using StorageBaseType::setEntitiesCount; + typename MeshTraitsType::PointArrayType points; friend Initializer< MeshConfig >; template< typename Mesh, int Dimension > friend struct IndexPermutationApplier; + + template< int EntityDimension, int SubentityDimension > + void setSubentitiesCounts( const typename MeshTraitsType::NeighborCountsArray& counts ); }; template< typename MeshConfig, typename Device > diff --git a/src/TNL/Meshes/Mesh.hpp b/src/TNL/Meshes/Mesh.hpp index b7394ea2c0454efd58e1e83b79e4c5bfa9c41108..efb2b432d99b53eceb353f58b499aa50da52eaf8 100644 --- a/src/TNL/Meshes/Mesh.hpp +++ b/src/TNL/Meshes/Mesh.hpp @@ -27,11 +27,12 @@ template< typename MeshConfig, typename Device, typename MeshType > void MeshInitializableBase< MeshConfig, Device, MeshType >:: init( typename MeshTraitsType::PointArrayType& points, - typename MeshTraitsType::CellSeedArrayType& cellSeeds ) + typename MeshTraitsType::FaceSeedMatrixType& faceSeeds, + typename MeshTraitsType::CellSeedMatrixType& cellSeeds ) { MeshType* mesh = static_cast< MeshType* >( this ); Initializer< typename MeshType::Config > initializer; - initializer.createMesh( points, cellSeeds, *mesh ); + initializer.createMesh( points, faceSeeds, cellSeeds, *mesh ); // init boundary tags static_cast< EntityTags::LayerFamily< MeshConfig, Device, MeshType >* >( mesh )->initLayer(); // init dual graph @@ -45,6 +46,7 @@ Mesh( const Mesh& mesh ) : StorageBaseType( mesh ), EntityTagsLayerFamily( mesh ) { + points = mesh.getPoints(); } template< typename MeshConfig, typename Device > @@ -54,16 +56,7 @@ Mesh( const Mesh< MeshConfig, Device_ >& mesh ) : StorageBaseType( mesh ), EntityTagsLayerFamily( mesh ) { -} - -template< typename MeshConfig, typename Device > -Mesh< MeshConfig, Device >& -Mesh< MeshConfig, Device >:: -operator=( const Mesh& mesh ) -{ - StorageBaseType::operator=( mesh ); - EntityTagsLayerFamily::operator=( mesh ); - return *this; + points = mesh.getPoints(); } template< typename MeshConfig, typename Device > @@ -72,6 +65,7 @@ Mesh< MeshConfig, Device >& Mesh< MeshConfig, Device >:: operator=( const Mesh< MeshConfig, Device_ >& mesh ) { + points = mesh.getPoints(); StorageBaseType::operator=( mesh ); EntityTagsLayerFamily::operator=( mesh ); return *this; @@ -106,6 +100,16 @@ getEntity( const GlobalIndexType entityIndex ) const return EntityType< Dimension >( *this, entityIndex ); } +template< typename MeshConfig, typename Device > + template< int Dimension > +void +Mesh< MeshConfig, Device >:: +setEntitiesCount( const typename MeshTraitsType::GlobalIndexType& entitiesCount ) +{ + StorageBaseType::setEntitiesCount( DimensionTag< Dimension >(), entitiesCount ); + if( Dimension == 0 ) + points.setSize( entitiesCount ); +} // duplicated for compatibility with grids template< typename MeshConfig, typename Device > @@ -128,6 +132,21 @@ getEntity( const GlobalIndexType entityIndex ) const return getEntity< Entity::getEntityDimension() >( entityIndex ); } +template< typename MeshConfig, typename Device > +const typename Mesh< MeshConfig, Device >::MeshTraitsType::PointArrayType& +Mesh< MeshConfig, Device >:: +getPoints() const +{ + return points; +} + +template< typename MeshConfig, typename Device > +typename Mesh< MeshConfig, Device >::MeshTraitsType::PointArrayType& +Mesh< MeshConfig, Device >:: +getPoints() +{ + return points; +} template< typename MeshConfig, typename Device > __cuda_callable__ @@ -151,6 +170,14 @@ getPoint( const GlobalIndexType vertexIndex ) return this->points[ vertexIndex ]; } +template< typename MeshConfig, typename Device > + template< int EntityDimension, int SubentityDimension > +void +Mesh< MeshConfig, Device >:: +setSubentitiesCounts( const typename MeshTraitsType::NeighborCountsArray& counts ) +{ + StorageBaseType::template setSubentitiesCounts< EntityDimension, SubentityDimension >( counts ); +} template< typename MeshConfig, typename Device > template< int EntityDimension, int SubentityDimension > @@ -159,7 +186,7 @@ constexpr typename Mesh< MeshConfig, Device >::LocalIndexType Mesh< MeshConfig, Device >:: getSubentitiesCount( const GlobalIndexType entityIndex ) const { - return StorageBaseType::template getSubentitiesCount< EntityDimension, SubentityDimension >(); + return StorageBaseType::template getSubentitiesCount< EntityDimension, SubentityDimension >( entityIndex ); } template< typename MeshConfig, typename Device > @@ -330,6 +357,7 @@ void Mesh< MeshConfig, Device >:: print( std::ostream& str ) const { + str << "Vertex coordinates are: " << points << std::endl; StorageBaseType::print( str ); EntityTagsLayerFamily::print( str ); } @@ -339,7 +367,8 @@ bool Mesh< MeshConfig, Device >:: operator==( const Mesh& mesh ) const { - return StorageBaseType::operator==( mesh ) && + return points == mesh.points && + StorageBaseType::operator==( mesh ) && EntityTagsLayerFamily::operator==( mesh ); } diff --git a/src/TNL/Meshes/MeshBuilder.h b/src/TNL/Meshes/MeshBuilder.h index 8dc39063365603458e35d2db5590692b9f2ca11d..aa10a8a245bd886439a3b7d66f32129e88bcef01 100644 --- a/src/TNL/Meshes/MeshBuilder.h +++ b/src/TNL/Meshes/MeshBuilder.h @@ -17,6 +17,7 @@ #pragma once #include +#include namespace TNL { namespace Meshes { @@ -25,24 +26,55 @@ template< typename Mesh > class MeshBuilder { public: - using MeshType = Mesh; - using MeshTraitsType = typename MeshType::MeshTraitsType; - using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; - using LocalIndexType = typename MeshTraitsType::LocalIndexType; - using PointType = typename MeshTraitsType::PointType; - using CellTopology = typename MeshTraitsType::CellTopology; - using CellSeedType = typename MeshTraitsType::CellSeedType; - - void setPointsCount( const GlobalIndexType& points ) + using MeshType = Mesh; + using MeshTraitsType = typename MeshType::MeshTraitsType; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using PointType = typename MeshTraitsType::PointType; + using CellTopology = typename MeshTraitsType::CellTopology; + using CellSeedMatrixType = typename MeshTraitsType::CellSeedMatrixType; + using CellSeedType = typename CellSeedMatrixType::EntitySeedMatrixSeed; + using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; + using FaceSeedType = typename FaceSeedMatrixType::EntitySeedMatrixSeed; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + + void setEntitiesCount( const GlobalIndexType& points, + const GlobalIndexType& cells = 0, + const GlobalIndexType& faces = 0 ) { this->points.setSize( points ); this->pointsSet.setSize( points ); pointsSet.setValue( false ); + + if( std::is_same< CellTopology, Topologies::Polyhedron >::value ) + { + this->faceSeeds.setDimensions( faces, points ); + this->cellSeeds.setDimensions( cells, faces ); + } + else // Topologies other than polyhedrons don't use face seeds + { + this->cellSeeds.setDimensions( cells, points ); + } + } + + void setFaceCornersCounts( const NeighborCountsArray& counts ) + { + this->faceSeeds.setEntityCornersCounts( counts ); } - void setCellsCount( const GlobalIndexType& cellsCount ) + void setFaceCornersCounts( NeighborCountsArray&& counts ) { - this->cellSeeds.setSize( cellsCount ); + this->faceSeeds.setEntityCornersCounts( std::move( counts ) ); + } + + void setCellCornersCounts( const NeighborCountsArray& counts ) + { + this->cellSeeds.setEntityCornersCounts( counts ); + } + + void setCellCornersCounts( NeighborCountsArray&& counts ) + { + this->cellSeeds.setEntityCornersCounts( std::move( counts ) ); } GlobalIndexType getPointsCount() const @@ -50,9 +82,14 @@ public: return this->points.getSize(); } + GlobalIndexType getFacesCount() const + { + return this->faceSeeds.getEntitiesCount(); + } + GlobalIndexType getCellsCount() const { - return this->cellSeeds.getSize(); + return this->cellSeeds.getEntitiesCount(); } void setPoint( GlobalIndexType index, @@ -62,23 +99,27 @@ public: this->pointsSet[ index ] = true; } - CellSeedType& getCellSeed( GlobalIndexType index ) + FaceSeedType getFaceSeed( GlobalIndexType index ) { - return this->cellSeeds[ index ]; + return this->faceSeeds.getSeed( index ); + } + + CellSeedType getCellSeed( GlobalIndexType index ) + { + return this->cellSeeds.getSeed( index ); } bool build( MeshType& mesh ) { if( ! this->validate() ) return false; - mesh.init( this->points, this->cellSeeds ); + mesh.init( this->points, this->faceSeeds, this->cellSeeds ); return true; } private: - using PointArrayType = typename MeshTraitsType::PointArrayType; - using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; - using BoolVector = Containers::Vector< bool, Devices::Host, GlobalIndexType >; + using PointArrayType = typename MeshTraitsType::PointArrayType; + using BoolVector = Containers::Vector< bool, Devices::Host, GlobalIndexType >; bool validate() const { @@ -91,27 +132,72 @@ private: assignedPoints.setLike( pointsSet ); assignedPoints.setValue( false ); - for( GlobalIndexType i = 0; i < getCellsCount(); i++ ) { - const auto cornerIds = this->cellSeeds[ i ].getCornerIds(); - for( LocalIndexType j = 0; j < cornerIds.getSize(); j++ ) { - assignedPoints[ cornerIds[ j ] ] = true; - if( cornerIds[ j ] < 0 || getPointsCount() <= cornerIds[ j ] ) { - std::cerr << "Cell seed " << i << " is referencing unavailable point " << cornerIds[ j ] << std::endl; - return false; + if( faceSeeds.empty() ) + { + for( GlobalIndexType i = 0; i < getCellsCount(); i++ ) { + const auto cellSeed = this->cellSeeds.getSeed( i ); + for( LocalIndexType j = 0; j < cellSeed.getCornersCount(); j++ ) { + const GlobalIndexType cornerId = cellSeed.getCornerId( j ); + assignedPoints[ cornerId ] = true; + if( cornerId < 0 || getPointsCount() <= cornerId ) { + std::cerr << "Cell seed " << i << " is referencing unavailable point " << cornerId << std::endl; + return false; + } } } + + if( min( assignedPoints ) != true ) { + std::cerr << "Mesh builder error: Some points were not used for cells." << std::endl; + return false; + } } + else + { + for( GlobalIndexType i = 0; i < getFacesCount(); i++ ) { + const auto faceSeed = this->faceSeeds.getSeed( i ); + for( LocalIndexType j = 0; j < faceSeed.getCornersCount(); j++ ) { + const GlobalIndexType cornerId = faceSeed.getCornerId( j ); + if( cornerId < 0 || getPointsCount() <= cornerId ) { + std::cerr << "face seed " << i << " is referencing unavailable point " << cornerId << std::endl; + return false; + } + assignedPoints[ cornerId ] = true; + } + } - if( min( assignedPoints ) != true ) { - std::cerr << "Mesh builder error: Some points were not used for cells." << std::endl; - return false; + if( min( assignedPoints ) != true ) { + std::cerr << "Mesh builder error: Some points were not used for faces." << std::endl; + return false; + } + + BoolVector assignedFaces; + assignedFaces.setSize( faceSeeds.getEntitiesCount() ); + assignedFaces.setValue( false ); + + for( GlobalIndexType i = 0; i < getCellsCount(); i++ ) { + const auto cellSeed = this->cellSeeds.getSeed( i ); + for( LocalIndexType j = 0; j < cellSeed.getCornersCount(); j++ ) { + const GlobalIndexType cornerId = cellSeed.getCornerId( j ); + if( cornerId < 0 || getFacesCount() <= cornerId ) { + std::cerr << "cell seed " << i << " is referencing unavailable face " << cornerId << std::endl; + return false; + } + assignedFaces[ cornerId ] = true; + } + } + + if( min( assignedFaces ) != true ) { + std::cerr << "Mesh builder error: Some faces were not used for cells." << std::endl; + return false; + } } return true; } PointArrayType points; - CellSeedArrayType cellSeeds; + FaceSeedMatrixType faceSeeds; + CellSeedMatrixType cellSeeds; BoolVector pointsSet; }; diff --git a/src/TNL/Meshes/MeshDetails/ConfigValidator.h b/src/TNL/Meshes/MeshDetails/ConfigValidator.h index 665574c0d8291e89c47110701db286f1c732c3b1..cb439b56735d98caed025e349eac28bf30aee15c 100644 --- a/src/TNL/Meshes/MeshDetails/ConfigValidator.h +++ b/src/TNL/Meshes/MeshDetails/ConfigValidator.h @@ -18,6 +18,7 @@ #include #include +#include namespace TNL { namespace Meshes { @@ -89,6 +90,9 @@ class ConfigValidatorLayerCell static_assert( MeshConfig::subentityStorage( CellTopology::dimension, 0 ), "subvertices of cells must be stored" ); + + static_assert( !std::is_same< CellTopology, Topologies::Polyhedron >::value || MeshConfig::subentityStorage( CellTopology::dimension, 2 ), + "faces of cells must be stored for polyhedral meshes" ); }; template< typename MeshConfig > diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h index d7bab6523b863ecb864da50063d0c82e48656063..36d31fcd069bb7e732ee035aed2f71d229e31670 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h @@ -18,6 +18,8 @@ #include #include +#include +#include namespace TNL { namespace Meshes { @@ -28,6 +30,7 @@ class Initializer; template< typename MeshConfig, typename SubdimensionTag, typename SuperdimensionTag, + typename SuperentityTopology = typename MeshTraits< MeshConfig >::template EntityTraits< SuperdimensionTag::value >::EntityTopology, // storage in the superentity bool SubentityStorage = MeshConfig::subentityStorage( SuperdimensionTag::value, SubdimensionTag::value ), // storage in the subentity @@ -48,17 +51,27 @@ class EntityInitializer DimensionTag< EntityTopology::dimension >, DimensionTag< MeshTraits< MeshConfig >::meshDimension > >; - using MeshTraitsType = MeshTraits< MeshConfig >; - using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; - using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using MeshTraitsType = MeshTraits< MeshConfig >; + using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; - using SeedType = EntitySeed< MeshConfig, EntityTopology >; - using InitializerType = Initializer< MeshConfig >; + using SeedType = EntitySeed< MeshConfig, EntityTopology >; + using InitializerType = Initializer< MeshConfig >; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + using SeedMatrixType = typename EntityTraitsType::SeedMatrixType; public: - static void initSubvertexMatrix( const GlobalIndexType entitiesCount, InitializerType& initializer ) + static void initSubvertexMatrix( NeighborCountsArray& capacities, InitializerType& initializer ) { - initializer.template initSubentityMatrix< EntityTopology::dimension, 0 >( entitiesCount ); + initializer.template initSubentityMatrix< EntityTopology::dimension, 0 >( capacities ); + } + + static void initSubvertexMatrix( SeedMatrixType& seeds, InitializerType& initializer ) + { + auto& subvertexMatrix = initializer.template getSubentitiesMatrix< EntityTopology::dimension, 0 >(); + subvertexMatrix = std::move( seeds.getMatrix() ); + initializer.template initSubentitiesCounts< EntityTopology::dimension, 0 >( seeds.getEntityCornerCounts() ); } static void initEntity( const GlobalIndexType entityIndex, const SeedType& entitySeed, InitializerType& initializer ) @@ -77,12 +90,16 @@ class EntityInitializer< MeshConfig, EntityTopology, false > DimensionTag< MeshTraits< MeshConfig >::meshDimension > > { using MeshTraitsType = MeshTraits< MeshConfig >; + using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using SeedType = EntitySeed< MeshConfig, EntityTopology >; using InitializerType = Initializer< MeshConfig >; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + using SeedMatrixType = typename EntityTraitsType::SeedMatrixType; public: - static void initSubvertexMatrix( const GlobalIndexType entitiesCount, InitializerType& initializer ) {} + static void initSubvertexMatrix( const NeighborCountsArray& capacities, InitializerType& initializer ) {} + static void initSubvertexMatrix( SeedMatrixType& seeds, InitializerType& initializer ) {} static void initEntity( const GlobalIndexType entityIndex, const SeedType& entitySeed, InitializerType& initializer ) {} }; @@ -95,10 +112,12 @@ public: */ template< typename MeshConfig, typename SubdimensionTag, - typename SuperdimensionTag > + typename SuperdimensionTag, + typename SuperentityTopology > class EntityInitializerLayer< MeshConfig, SubdimensionTag, SuperdimensionTag, + SuperentityTopology, true, true, true > @@ -111,15 +130,116 @@ class EntityInitializerLayer< MeshConfig, typename SuperdimensionTag::Decrement >; using InitializerType = Initializer< MeshConfig >; using MeshType = typename InitializerType::MeshType; + using MeshTraitsType = MeshTraits< MeshConfig >; - using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; - using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; - using SubentityTraitsType = typename MeshTraits< MeshConfig >::template EntityTraits< SubdimensionTag::value >; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using SubentityTraitsType = typename MeshTraitsType::template EntityTraits< SubdimensionTag::value >; using SubentityTopology = typename SubentityTraitsType::EntityTopology; - using SuperentityTraitsType = typename MeshTraits< MeshConfig >::template EntityTraits< SuperdimensionTag::value >; + using SuperentityTraitsType = typename MeshTraitsType::template EntityTraits< SuperdimensionTag::value >; + using SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperentityTopology, SubdimensionTag >; + using SuperentityMatrixType = typename MeshTraitsType::SuperentityMatrixType; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + using SeedType = EntitySeed< MeshConfig, SubentityTopology >; + +public: + static void initSuperentities( InitializerType& meshInitializer, MeshType& mesh ) + { + //std::cout << " Initiating superentities with dimension " << SuperdimensionTag::value << " for subentities with dimension " << SubdimensionTag::value << " ... " << std::endl; + + const GlobalIndexType subentitiesCount = mesh.template getEntitiesCount< SubdimensionTag::value >(); + const GlobalIndexType superentitiesCount = mesh.template getEntitiesCount< SuperdimensionTag::value >(); + + if( SubdimensionTag::value > 0 || std::is_same< SuperentityTopology, Topologies::Polyhedron >::value ) + { + NeighborCountsArray capacities( superentitiesCount ); + + Algorithms::ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, superentitiesCount, [&] ( GlobalIndexType superentityIndex ) + { + capacities[ superentityIndex ] = SubentitySeedsCreatorType::getSubentitiesCount( meshInitializer, mesh, superentityIndex ); + }); + + meshInitializer.template initSubentityMatrix< SuperdimensionTag::value, SubdimensionTag::value >( capacities, subentitiesCount ); + } + + // counter for superentities of each subentity + auto& superentitiesCounts = meshInitializer.template getSuperentitiesCountsArray< SubdimensionTag::value, SuperdimensionTag::value >(); + superentitiesCounts.setSize( subentitiesCount ); + superentitiesCounts.setValue( 0 ); + + Algorithms::ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, superentitiesCount, [&] ( GlobalIndexType superentityIndex ) + { + LocalIndexType i = 0; + SubentitySeedsCreatorType::iterate( meshInitializer, mesh, superentityIndex, [&] ( SeedType& seed ) { + const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( seed ); + + // Subentity indices for SubdimensionTag::value == 0 of non-polyhedral meshes were already set up from seeds + if( SubdimensionTag::value > 0 || std::is_same< SuperentityTopology, Topologies::Polyhedron >::value ) + meshInitializer.template setSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i++, subentityIndex ); + + Algorithms::AtomicOperations< Devices::Host >::add( superentitiesCounts[ subentityIndex ], LocalIndexType{ 1 } ); + }); + }); + + // allocate superentities storage + SuperentityMatrixType& matrix = meshInitializer.template getSuperentitiesMatrix< SubdimensionTag::value, SuperdimensionTag::value >(); + matrix.setDimensions( subentitiesCount, superentitiesCount ); + matrix.setRowCapacities( superentitiesCounts ); + superentitiesCounts.setValue( 0 ); + + for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) + { + for( LocalIndexType i = 0; + i < mesh.template getSubentitiesCount< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex ); + i++ ) + { + const GlobalIndexType subentityIndex = mesh.template getSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i ); + auto row = matrix.getRow( subentityIndex ); + row.setElement( superentitiesCounts[ subentityIndex ]++, superentityIndex, true ); + } + } + + BaseType::initSuperentities( meshInitializer, mesh ); + } +}; + +/**** + * Mesh entity initializer layer with specializations + * + * SUBENTITY STORAGE SUPERENTITY STORAGE Subdimension Superdimension SUPERENTITY TOPOLOGY + * TRUE TRUE 2 3 POLYHEDRON + */ +template< typename MeshConfig > +class EntityInitializerLayer< MeshConfig, + DimensionTag< 2 >, + DimensionTag< 3 >, + Topologies::Polyhedron, + true, + true, + true > + : public EntityInitializerLayer< MeshConfig, + DimensionTag< 2 >, + typename DimensionTag< 3 >::Decrement > +{ + using SubdimensionTag = DimensionTag< 2 >; + using SuperdimensionTag = DimensionTag< 3 >; + + using BaseType = EntityInitializerLayer< MeshConfig, + SubdimensionTag, + typename SuperdimensionTag::Decrement >; + using InitializerType = Initializer< MeshConfig >; + using MeshType = typename InitializerType::MeshType; + using MeshTraitsType = MeshTraits< MeshConfig >; + + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using SubentityTraitsType = typename MeshTraitsType::template EntityTraits< SubdimensionTag::value >; + using SubentityTopology = typename SubentityTraitsType::EntityTopology; + using SuperentityTraitsType = typename MeshTraitsType::template EntityTraits< SuperdimensionTag::value >; using SuperentityTopology = typename SuperentityTraitsType::EntityTopology; - using SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperdimensionTag, SubdimensionTag >; - using SuperentityMatrixType = typename MeshTraits< MeshConfig >::SuperentityMatrixType; + using SuperentityMatrixType = typename MeshTraitsType::SuperentityMatrixType; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + using SeedType = EntitySeed< MeshConfig, SubentityTopology >; public: static void initSuperentities( InitializerType& meshInitializer, MeshType& mesh ) @@ -128,25 +248,27 @@ public: const GlobalIndexType subentitiesCount = mesh.template getEntitiesCount< SubdimensionTag::value >(); const GlobalIndexType superentitiesCount = mesh.template getEntitiesCount< SuperdimensionTag::value >(); - if( SubdimensionTag::value > 0 ) - meshInitializer.template initSubentityMatrix< SuperdimensionTag::value, SubdimensionTag::value >( superentitiesCount, subentitiesCount ); // counter for superentities of each subentity auto& superentitiesCounts = meshInitializer.template getSuperentitiesCountsArray< SubdimensionTag::value, SuperdimensionTag::value >(); superentitiesCounts.setSize( subentitiesCount ); superentitiesCounts.setValue( 0 ); + auto& cellSeeds = meshInitializer.getCellSeeds(); for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); - for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) + const auto cellSeed = cellSeeds.getSeed( superentityIndex ); + for( LocalIndexType i = 0; i < cellSeed.getCornersCount(); i++ ) { - const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( subentitySeeds[ i ] ); - meshInitializer.template setSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i, subentityIndex ); + const GlobalIndexType subentityIndex = cellSeed.getCornerId( i ); superentitiesCounts[ subentityIndex ]++; } } + auto& subvertexMatrix = meshInitializer.template getSubentitiesMatrix< SuperdimensionTag::value, SubdimensionTag::value >(); + subvertexMatrix = std::move( cellSeeds.getMatrix() ); + meshInitializer.template initSubentitiesCounts< SuperdimensionTag::value, SubdimensionTag::value >( cellSeeds.getEntityCornerCounts() ); + // allocate superentities storage SuperentityMatrixType& matrix = meshInitializer.template getSuperentitiesMatrix< SubdimensionTag::value, SuperdimensionTag::value >(); matrix.setDimensions( subentitiesCount, superentitiesCount ); @@ -178,10 +300,12 @@ public: */ template< typename MeshConfig, typename SubdimensionTag, - typename SuperdimensionTag > + typename SuperdimensionTag, + typename SuperentityTopology > class EntityInitializerLayer< MeshConfig, SubdimensionTag, SuperdimensionTag, + SuperentityTopology, true, false, true > @@ -194,12 +318,16 @@ class EntityInitializerLayer< MeshConfig, typename SuperdimensionTag::Decrement >; using InitializerType = Initializer< MeshConfig >; using MeshType = typename InitializerType::MeshType; + using MeshTraitsType = MeshTraits< MeshConfig >; - using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; - using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; - using SuperentityTraitsType = typename MeshTraits< MeshConfig >::template EntityTraits< SuperdimensionTag::value >; - using SuperentityTopology = typename SuperentityTraitsType::EntityTopology; - using SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperdimensionTag, SubdimensionTag >; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using SubentityTraitsType = typename MeshTraitsType::template EntityTraits< SubdimensionTag::value >; + using SubentityTopology = typename SubentityTraitsType::EntityTopology; + using SuperentityTraitsType = typename MeshTraitsType::template EntityTraits< SuperdimensionTag::value >; + using SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperentityTopology, SubdimensionTag >; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + using SeedType = EntitySeed< MeshConfig, SubentityTopology >; public: static void initSuperentities( InitializerType& meshInitializer, MeshType& mesh ) @@ -208,26 +336,81 @@ public: const GlobalIndexType subentitiesCount = mesh.template getEntitiesCount< SubdimensionTag::value >(); const GlobalIndexType superentitiesCount = mesh.template getEntitiesCount< SuperdimensionTag::value >(); - if( SubdimensionTag::value > 0 ) - meshInitializer.template initSubentityMatrix< SuperdimensionTag::value, SubdimensionTag::value >( superentitiesCount, subentitiesCount ); - - for( GlobalIndexType superentityIndex = 0; - superentityIndex < mesh.template getEntitiesCount< SuperdimensionTag::value >(); - superentityIndex++ ) + if( SubdimensionTag::value > 0 || std::is_same< SuperentityTopology, Topologies::Polyhedron >::value ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); + NeighborCountsArray capacities( superentitiesCount ); - for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) + Algorithms::ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, superentitiesCount, [&] ( GlobalIndexType superentityIndex ) { - const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( subentitySeeds[ i ] ); - meshInitializer.template setSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i, subentityIndex ); - } + capacities[ superentityIndex ] = SubentitySeedsCreatorType::getSubentitiesCount( meshInitializer, mesh, superentityIndex ); + }); + + meshInitializer.template initSubentityMatrix< SuperdimensionTag::value, SubdimensionTag::value >( capacities, subentitiesCount ); + + Algorithms::ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, superentitiesCount, [&] ( GlobalIndexType superentityIndex ) + { + LocalIndexType i = 0; + SubentitySeedsCreatorType::iterate( meshInitializer, mesh, superentityIndex, [&] ( SeedType& seed ) + { + const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( seed ); + meshInitializer.template setSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i++, subentityIndex ); + }); + }); } BaseType::initSuperentities( meshInitializer, mesh ); } }; +/**** + * Mesh entity initializer layer with specializations + * + * SUBENTITY STORAGE SUPERENTITY STORAGE Subdimension Superdimension SUPERENTITY TOPOLOGY + * TRUE FALSE 2 3 POLYHEDRON + */ +template< typename MeshConfig > +class EntityInitializerLayer< MeshConfig, + DimensionTag< 2 >, + DimensionTag< 3 >, + Topologies::Polyhedron, + true, + false, + true > + : public EntityInitializerLayer< MeshConfig, + DimensionTag< 2 >, + typename DimensionTag< 3 >::Decrement > +{ + using SubdimensionTag = DimensionTag< 2 >; + using SuperdimensionTag = DimensionTag< 3 >; + + using BaseType = EntityInitializerLayer< MeshConfig, + SubdimensionTag, + typename SuperdimensionTag::Decrement >; + using InitializerType = Initializer< MeshConfig >; + using MeshType = typename InitializerType::MeshType; + using MeshTraitsType = MeshTraits< MeshConfig >; + + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using SubentityTraitsType = typename MeshTraitsType::template EntityTraits< SubdimensionTag::value >; + using SubentityTopology = typename SubentityTraitsType::EntityTopology; + using SuperentityTraitsType = typename MeshTraitsType::template EntityTraits< SuperdimensionTag::value >; + using SuperentityTopology = typename SuperentityTraitsType::EntityTopology; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + using SeedType = EntitySeed< MeshConfig, SubentityTopology >; + +public: + static void initSuperentities( InitializerType& meshInitializer, MeshType& mesh ) + { + //std::cout << " Initiating superentities with dimension " << SuperdimensionTag::value << " for subentities with dimension " << SubdimensionTag::value << " ... " << std::endl; + auto& cellSeeds = meshInitializer.getCellSeeds(); + auto& subvertexMatrix = meshInitializer.template getSubentitiesMatrix< SuperdimensionTag::value, SubdimensionTag::value >(); + subvertexMatrix = std::move( cellSeeds.getMatrix() ); + meshInitializer.template initSubentitiesCounts< SuperdimensionTag::value, SubdimensionTag::value >( cellSeeds.getEntityCornerCounts() ); + BaseType::initSuperentities( meshInitializer, mesh ); + } +}; + /**** * Mesh entity initializer layer with specializations * @@ -236,10 +419,12 @@ public: */ template< typename MeshConfig, typename SubdimensionTag, - typename SuperdimensionTag > + typename SuperdimensionTag, + typename SuperentityTopology > class EntityInitializerLayer< MeshConfig, SubdimensionTag, SuperdimensionTag, + SuperentityTopology, false, true, true > @@ -252,15 +437,16 @@ class EntityInitializerLayer< MeshConfig, typename SuperdimensionTag::Decrement >; using InitializerType = Initializer< MeshConfig >; using MeshType = typename InitializerType::MeshType; + using MeshTraitsType = MeshTraits< MeshConfig >; - using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; - using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; - using SubentityTraitsType = typename MeshTraits< MeshConfig >::template EntityTraits< SubdimensionTag::value >; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using SubentityTraitsType = typename MeshTraitsType::template EntityTraits< SubdimensionTag::value >; using SubentityTopology = typename SubentityTraitsType::EntityTopology; - using SuperentityTraitsType = typename MeshTraits< MeshConfig >::template EntityTraits< SuperdimensionTag::value >; - using SuperentityTopology = typename SuperentityTraitsType::EntityTopology; - using SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperdimensionTag, SubdimensionTag >; - using SuperentityMatrixType = typename MeshTraits< MeshConfig >::SuperentityMatrixType; + using SuperentityTraitsType = typename MeshTraitsType::template EntityTraits< SuperdimensionTag::value >; + using SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperentityTopology, SubdimensionTag >; + using SuperentityMatrixType = typename MeshTraitsType::SuperentityMatrixType; + using SeedType = EntitySeed< MeshConfig, SubentityTopology >; public: static void initSuperentities( InitializerType& meshInitializer, MeshType& mesh ) @@ -275,15 +461,13 @@ public: superentitiesCounts.setSize( subentitiesCount ); superentitiesCounts.setValue( 0 ); - for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) + Algorithms::ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, superentitiesCount, [&] ( GlobalIndexType superentityIndex ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); - for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) - { - const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( subentitySeeds[ i ] ); - superentitiesCounts[ subentityIndex ]++; - } - } + SubentitySeedsCreatorType::iterate( meshInitializer, mesh, superentityIndex, [&] ( SeedType& seed ) { + const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( seed ); + Algorithms::AtomicOperations< Devices::Host >::add( superentitiesCounts[ subentityIndex ], LocalIndexType{ 1 } ); + }); + }); // allocate superentities storage SuperentityMatrixType& matrix = meshInitializer.template getSuperentitiesMatrix< SubdimensionTag::value, SuperdimensionTag::value >(); @@ -294,25 +478,43 @@ public: // initialize superentities storage for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); - for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) - { - const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( subentitySeeds[ i ] ); + SubentitySeedsCreatorType::iterate( meshInitializer, mesh, superentityIndex, [&] ( SeedType& seed ) { + const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( seed ); auto row = matrix.getRow( subentityIndex ); row.setElement( superentitiesCounts[ subentityIndex ]++, superentityIndex, true ); - } + }); } + // Here is an attempt of parallelization of previous for cycle, that seemingly causes some kind of race condition + /*Algorithms::ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, superentitiesCount, [&] ( GlobalIndexType superentityIndex ) + { + SubentitySeedsCreatorType::iterate( meshInitializer, mesh, superentityIndex, [&] ( SeedType& seed ) { + const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( seed ); + auto row = matrix.getRow( subentityIndex ); + + LocalIndexType superentityCount; + #pragma omp atomic capture + { + superentityCount = superentitiesCounts[ subentityIndex ]; + superentitiesCounts[ subentityIndex ]++; + } + + row.setElement( superentityCount, superentityIndex, true ); + }); + });*/ + BaseType::initSuperentities( meshInitializer, mesh ); } }; template< typename MeshConfig, typename SubdimensionTag, - typename SuperdimensionTag > + typename SuperdimensionTag, + typename SuperentityTopology > class EntityInitializerLayer< MeshConfig, SubdimensionTag, SuperdimensionTag, + SuperentityTopology, false, false, true > @@ -323,11 +525,13 @@ class EntityInitializerLayer< MeshConfig, template< typename MeshConfig, typename SubdimensionTag, + typename SuperentityTopology, bool SubentityStorage, bool SuperentityStorage > class EntityInitializerLayer< MeshConfig, SubdimensionTag, SubdimensionTag, + SuperentityTopology, SubentityStorage, SuperentityStorage, false > diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h index 41439c4056905523596b9bbbf76df035f14ca4cd..04143e2a3aa1ac26c986aa28a02b7bb3e5e12049 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h @@ -16,7 +16,10 @@ #pragma once +#include + #include +#include namespace TNL { namespace Meshes { @@ -28,18 +31,21 @@ struct EntitySeedEq; template< typename MeshConfig, typename EntityTopology > -class EntitySeed +class EntitySeed< MeshConfig, EntityTopology, false > { - using MeshConfigTraits = MeshTraits< MeshConfig >; - using SubvertexTraits = typename MeshTraits< MeshConfig >::template SubentityTraits< EntityTopology, 0 >; + using MeshTraitsType = MeshTraits< MeshConfig >; + using SubvertexTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 0 >; public: - using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; - using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; using IdArrayType = Containers::StaticArray< SubvertexTraits::count, GlobalIndexType >; using HashType = EntitySeedHash< EntitySeed >; using KeyEqual = EntitySeedEq< EntitySeed >; + //this function is here only for compatibility with MeshReader + void setCornersCount( const LocalIndexType& cornersCount ) {} + static constexpr LocalIndexType getCornersCount() { return SubvertexTraits::count; @@ -69,17 +75,20 @@ class EntitySeed }; template< typename MeshConfig > -class EntitySeed< MeshConfig, Topologies::Vertex > +class EntitySeed< MeshConfig, Topologies::Vertex, false > { - using MeshConfigTraits = MeshTraits< MeshConfig >; + using MeshTraitsType = MeshTraits< MeshConfig >; public: - using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; - using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; using IdArrayType = Containers::StaticArray< 1, GlobalIndexType >; using HashType = EntitySeedHash< EntitySeed >; using KeyEqual = EntitySeedEq< EntitySeed >; + //this function is here only for compatibility with MeshReader + void setCornersCount( const LocalIndexType& cornersCount ) {} + static constexpr LocalIndexType getCornersCount() { return 1; @@ -107,6 +116,65 @@ class EntitySeed< MeshConfig, Topologies::Vertex > IdArrayType cornerIds; }; +template< typename MeshConfig, + typename EntityTopology > +class EntitySeed< MeshConfig, EntityTopology, true > +{ + using MeshTraitsType = MeshTraits< MeshConfig >; + +public: + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using IdArrayType = Containers::Array< GlobalIndexType, Devices::Host, LocalIndexType >; + using HashType = EntitySeedHash< EntitySeed >; + using KeyEqual = EntitySeedEq< EntitySeed >; + + // this constructor definition is here to avoid default constructor being implicitly declared as __host__ __device__, that causes warning: + // warning #20011-D: calling a __host__ function("std::allocator ::allocator") + // from a __host__ __device__ function("TNL::Meshes::EntitySeed< ::MeshTest::TestTwoWedgesMeshConfig, + // ::TNL::Meshes::Topologies::Polygon> ::EntitySeed [subobject]") is not allowed + EntitySeed() + { + } + + void setCornersCount( const LocalIndexType& cornersCount ) + { + if( std::is_same< EntityTopology, Topologies::Polygon >::value ) + TNL_ASSERT_GE( cornersCount, 3, "polygons must have at least 3 corners" ); + /*else if( std::is_same< EntityTopology, Topologies::Polyhedron >::value ) + TNL_ASSERT_GE( cornersCount, 2, "polyhedron must have at least 2 faces" );*/ + + this->cornerIds.setSize( cornersCount ); + } + + LocalIndexType getCornersCount() const + { + return this->cornerIds.getSize(); + } + + void setCornerId( const LocalIndexType& cornerIndex, const GlobalIndexType& pointIndex ) + { + TNL_ASSERT_GE( cornerIndex, 0, "corner index must be non-negative" ); + TNL_ASSERT_LT( cornerIndex, getCornersCount(), "corner index is out of bounds" ); + TNL_ASSERT_GE( pointIndex, 0, "point index must be non-negative" ); + + this->cornerIds[ cornerIndex ] = pointIndex; + } + + IdArrayType& getCornerIds() + { + return cornerIds; + } + + const IdArrayType& getCornerIds() const + { + return cornerIds; + } + +private: + IdArrayType cornerIds; +}; + template< typename MeshConfig, typename EntityTopology > std::ostream& operator<<( std::ostream& str, const EntitySeed< MeshConfig, EntityTopology >& e ) { @@ -125,7 +193,7 @@ struct EntitySeedHash // Note that we must use an associative function to combine the hashes, // because we *want* to ignore the order of the corner IDs. std::size_t hash = 0; - for( LocalIndexType i = 0; i < EntitySeed::getCornersCount(); i++ ) + for( LocalIndexType i = 0; i < seed.getCornersCount(); i++ ) // hash ^= std::hash< GlobalIndexType >{}( seed.getCornerIds()[ i ] ); hash += std::hash< GlobalIndexType >{}( seed.getCornerIds()[ i ] ); return hash; @@ -141,8 +209,12 @@ struct EntitySeedEq IdArrayType sortedLeft( left.getCornerIds() ); IdArrayType sortedRight( right.getCornerIds() ); - sortedLeft.sort(); - sortedRight.sort(); + + //use std::sort for now, because polygon EntitySeeds use TNL::Containers::Array for cornersIds, that is missing sort function + std::sort( sortedLeft.getData(), sortedLeft.getData() + sortedLeft.getSize() ); + std::sort( sortedRight.getData(), sortedRight.getData() + sortedRight.getSize() ); + /*sortedLeft.sort(); + sortedRight.sort();*/ return sortedLeft == sortedRight; } }; diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h new file mode 100644 index 0000000000000000000000000000000000000000..ae6ac5eeddba371f58d906dffd83f2cf213c05ad --- /dev/null +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h @@ -0,0 +1,450 @@ +#pragma once + +//#include +#include + +namespace TNL { +namespace Meshes { + +template< typename MeshConfig, + typename Device> +class MeshTraits; + +template< typename MeshConfig, + typename EntityTopology, + bool IsDynamicTopology = Topologies::IsDynamicTopology< EntityTopology >::value > +class EntitySeedMatrix; + +template< typename MeshConfig, + typename EntityTopology > +class EntitySeedMatrix< MeshConfig, EntityTopology, false > +{ + using MeshTraitsType = MeshTraits< MeshConfig, Devices::Host >; + + public: + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using SubentityTraitsType = typename MeshTraitsType::template SubentityTraits< EntityTopology, 0 >; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + + EntitySeedMatrix() = default; + + EntitySeedMatrix( const EntitySeedMatrix& other ) = default; + + EntitySeedMatrix( EntitySeedMatrix&& other ) = default; + + EntitySeedMatrix& operator=( const EntitySeedMatrix& other ) = default; + + EntitySeedMatrix& operator=( EntitySeedMatrix&& other ) = default; + + class EntitySeedMatrixSeed + { + using RowView = typename SubentityMatrixType::RowView; + + public: + EntitySeedMatrixSeed( const RowView& matrixRow ) + : row( matrixRow ) + {} + + static constexpr LocalIndexType getCornersCount() + { + return SubentityTraitsType::count; + } + + void setCornerId( const LocalIndexType& cornerIndex, const GlobalIndexType& pointIndex ) + { + TNL_ASSERT_GE( cornerIndex, 0, "corner index must be non-negative" ); + TNL_ASSERT_LT( cornerIndex, getCornersCount(), "corner index is out of bounds" ); + TNL_ASSERT_GE( pointIndex, 0, "point index must be non-negative" ); + this->row.setColumnIndex( cornerIndex, pointIndex ); + } + + GlobalIndexType getCornerId( const LocalIndexType& cornerIndex ) const + { + return this->row.getColumnIndex( cornerIndex ); + } + + private: + RowView row; + }; + + class ConstEntitySeedMatrixSeed + { + using ConstRowView = typename SubentityMatrixType::ConstRowView; + + public: + ConstEntitySeedMatrixSeed( const ConstRowView& matrixRow ) + : row( matrixRow ) + {} + + static constexpr LocalIndexType getCornersCount() + { + return SubentityTraitsType::count; + } + + GlobalIndexType getCornerId( const LocalIndexType& cornerIndex ) const + { + return this->row.getColumnIndex( cornerIndex ); + } + + private: + ConstRowView row; + }; + + void setDimensions( const GlobalIndexType& entitiesCount, const GlobalIndexType& pointsCount ) + { + matrix.setDimensions( entitiesCount, pointsCount ); + + NeighborCountsArray capacities( entitiesCount ); + capacities.setValue( SubentityTraitsType::count ); + matrix.setRowCapacities( capacities ); + } + + // This method is only here for compatibility with specialization for dynamic entity topologies + void setEntityCornersCounts( const NeighborCountsArray& counts ) + { + } + + // This method is only here for compatibility with specialization for dynamic entity topologies + void setEntityCornersCounts( NeighborCountsArray&& counts ) + { + } + + void reset() + { + matrix.reset(); + } + + GlobalIndexType getEntitiesCount() const + { + return matrix.getRows(); + } + + SubentityMatrixType& getMatrix() + { + return matrix; + } + + const SubentityMatrixType& getMatrix() const + { + return matrix; + } + + NeighborCountsArray getEntityCornerCounts() const + { + NeighborCountsArray counts( getEntitiesCount() ); + counts.setValue( SubentityTraitsType::count ); + return counts; + } + + bool empty() const + { + return getEntitiesCount() == 0; + } + + EntitySeedMatrixSeed getSeed( const GlobalIndexType& entityIndex ) + { + return EntitySeedMatrixSeed( matrix.getRow( entityIndex ) ); + } + + ConstEntitySeedMatrixSeed getSeed( const GlobalIndexType& entityIndex ) const + { + return ConstEntitySeedMatrixSeed( matrix.getRow( entityIndex ) ); + } + + private: + SubentityMatrixType matrix; +}; + +template< typename MeshConfig > +class EntitySeedMatrix< MeshConfig, Topologies::Vertex, false > +{ + using MeshTraitsType = MeshTraits< MeshConfig, Devices::Host >; + + public: + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< 0 >; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + + EntitySeedMatrix() = default; + + EntitySeedMatrix( const EntitySeedMatrix& other ) = default; + + EntitySeedMatrix( EntitySeedMatrix&& other ) = default; + + EntitySeedMatrix& operator=( const EntitySeedMatrix& other ) = default; + + EntitySeedMatrix& operator=( EntitySeedMatrix&& other ) = default; + + class EntitySeedMatrixSeed + { + using RowView = typename SubentityMatrixType::RowView; + + public: + EntitySeedMatrixSeed( const RowView& matrixRow ) + : row( matrixRow ) + {} + + static constexpr LocalIndexType getCornersCount() + { + return 1; + } + + void setCornerId( const LocalIndexType& cornerIndex, const GlobalIndexType& pointIndex ) + { + TNL_ASSERT_GE( cornerIndex, 0, "corner index must be non-negative" ); + TNL_ASSERT_LT( cornerIndex, getCornersCount(), "corner index is out of bounds" ); + TNL_ASSERT_GE( pointIndex, 0, "point index must be non-negative" ); + this->row.setColumnIndex( cornerIndex, pointIndex ); + } + + GlobalIndexType getCornerId( const LocalIndexType& cornerIndex ) const + { + return this->row.getColumnIndex( cornerIndex ); + } + + private: + RowView row; + }; + + class ConstEntitySeedMatrixSeed + { + using ConstRowView = typename SubentityMatrixType::ConstRowView; + + public: + ConstEntitySeedMatrixSeed( const ConstRowView& matrixRow ) + : row( matrixRow ) + {} + + static constexpr LocalIndexType getCornersCount() + { + return 1; + } + + GlobalIndexType getCornerId( const LocalIndexType& cornerIndex ) const + { + return this->row.getColumnIndex( cornerIndex ); + } + + private: + ConstRowView row; + }; + + void setDimensions( const GlobalIndexType& entitiesCount, const GlobalIndexType& pointsCount ) + { + matrix.setDimensions( entitiesCount, pointsCount ); + + NeighborCountsArray capacities( entitiesCount ); + capacities.setValue( 1 ); + matrix.setRowCapacities( capacities ); + } + + // This method is only here for compatibility with specialization for dynamic entity topologies + void setEntityCornersCounts( const NeighborCountsArray& counts ) + { + } + + // This method is only here for compatibility with specialization for dynamic entity topologies + void setEntityCornersCounts( NeighborCountsArray&& counts ) + { + } + + void reset() + { + matrix.reset(); + } + + GlobalIndexType getEntitiesCount() const + { + return matrix.getRows(); + } + + SubentityMatrixType& getMatrix() + { + return matrix; + } + + const SubentityMatrixType& getMatrix() const + { + return matrix; + } + + NeighborCountsArray getEntityCornerCounts() const + { + NeighborCountsArray counts( getEntitiesCount() ); + counts.setValue( 1 ); + return counts; + } + + bool empty() const + { + return getEntitiesCount() == 0; + } + + EntitySeedMatrixSeed getSeed( const GlobalIndexType& entityIndex ) + { + return EntitySeedMatrixSeed( matrix.getRow( entityIndex ) ); + } + + ConstEntitySeedMatrixSeed getSeed( const GlobalIndexType& entityIndex ) const + { + return ConstEntitySeedMatrixSeed( matrix.getRow( entityIndex ) ); + } + + private: + SubentityMatrixType matrix; +}; + +template< typename MeshConfig, + typename EntityTopology > +class EntitySeedMatrix< MeshConfig, EntityTopology, true > +{ + using MeshTraitsType = MeshTraits< MeshConfig, Devices::Host >; + + public: + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + + EntitySeedMatrix() = default; + + EntitySeedMatrix( const EntitySeedMatrix& other ) = default; + + EntitySeedMatrix( EntitySeedMatrix&& other ) = default; + + EntitySeedMatrix& operator=( const EntitySeedMatrix& other ) = default; + + EntitySeedMatrix& operator=( EntitySeedMatrix&& other ) = default; + + class EntitySeedMatrixSeed + { + using RowView = typename SubentityMatrixType::RowView; + + public: + EntitySeedMatrixSeed( const RowView& matrixRow, const LocalIndexType& corners ) + : row( matrixRow ), + cornersCount( corners ) + {} + + LocalIndexType getCornersCount() const + { + return cornersCount; + } + + void setCornerId( const LocalIndexType& cornerIndex, const GlobalIndexType& pointIndex ) + { + TNL_ASSERT_GE( cornerIndex, 0, "corner index must be non-negative" ); + TNL_ASSERT_LT( cornerIndex, getCornersCount(), "corner index is out of bounds" ); + TNL_ASSERT_GE( pointIndex, 0, "point index must be non-negative" ); + this->row.setColumnIndex( cornerIndex, pointIndex ); + } + + GlobalIndexType getCornerId( const LocalIndexType& cornerIndex ) const + { + return this->row.getColumnIndex( cornerIndex ); + } + + private: + RowView row; + LocalIndexType cornersCount; + }; + + class ConstEntitySeedMatrixSeed + { + using ConstRowView = typename SubentityMatrixType::ConstRowView; + + public: + ConstEntitySeedMatrixSeed( const ConstRowView& matrixRow, const LocalIndexType& corners ) + : row( matrixRow ), + cornersCount( corners ) + {} + + LocalIndexType getCornersCount() const + { + return cornersCount; + } + + GlobalIndexType getCornerId( const LocalIndexType& cornerIndex ) const + { + return this->row.getColumnIndex( cornerIndex ); + } + + private: + ConstRowView row; + LocalIndexType cornersCount; + }; + + void setDimensions( const GlobalIndexType& entitiesCount, const GlobalIndexType& pointsCount ) + { + counts.setSize( entitiesCount ); + matrix.setDimensions( entitiesCount, pointsCount ); + } + + void setEntityCornersCounts( const NeighborCountsArray& counts_ ) + { + this->counts = counts_; + matrix.setRowCapacities( this->counts ); + } + + void setEntityCornersCounts( NeighborCountsArray&& counts_ ) + { + this->counts = std::move( counts_ ); + matrix.setRowCapacities( this->counts ); + } + + void reset() + { + matrix.reset(); + counts.reset(); + } + + GlobalIndexType getEntitiesCount() const + { + return matrix.getRows(); + } + + SubentityMatrixType& getMatrix() + { + return matrix; + } + + const SubentityMatrixType& getMatrix() const + { + return matrix; + } + + NeighborCountsArray& getEntityCornerCounts() + { + return counts; + } + + const NeighborCountsArray& getEntityCornerCounts() const + { + return counts; + } + + bool empty() const + { + return getEntitiesCount() == 0; + } + + EntitySeedMatrixSeed getSeed( const GlobalIndexType& entityIndex ) + { + return EntitySeedMatrixSeed( matrix.getRow( entityIndex ), counts[ entityIndex ] ); + } + + ConstEntitySeedMatrixSeed getSeed( const GlobalIndexType& entityIndex ) const + { + return ConstEntitySeedMatrixSeed( matrix.getRow( entityIndex ), counts[ entityIndex ] ); + } + + private: + SubentityMatrixType matrix; + NeighborCountsArray counts; +}; + +} // namespace Meshes +} // namespace TNL diff --git a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index f8d5775ca91649370cf7e406dd09134e47ec897f..9417c244e313d88ae7b55444a044263ad24d4fde 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -70,21 +70,26 @@ class Initializer protected: // must be declared before its use in expression with decltype() Mesh< MeshConfig >* mesh = nullptr; - + public: using MeshType = Mesh< MeshConfig >; using MeshTraitsType = MeshTraits< MeshConfig >; using DimensionTag = Meshes::DimensionTag< MeshTraitsType::meshDimension >; using BaseType = InitializerLayer< MeshConfig, DimensionTag >; using PointArrayType = typename MeshTraitsType::PointArrayType; - using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; + using CellSeedMatrixType = typename MeshTraitsType::CellSeedMatrixType; + using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + template< int Dimension, int Subdimension > + using SubentityMatrixRowsCapacitiesType = typename MeshTraitsType::template SubentityMatrixType< Dimension >::RowsCapacitiesType; // The points and cellSeeds arrays will be reset when not needed to save memory. void createMesh( PointArrayType& points, - CellSeedArrayType& cellSeeds, + FaceSeedMatrixType& faceSeeds, + CellSeedMatrixType& cellSeeds, MeshType& mesh ) { // copy points @@ -93,23 +98,31 @@ class Initializer points.reset(); this->mesh = &mesh; - BaseType::initEntities( *this, cellSeeds, mesh ); + this->cellSeeds = &cellSeeds; + + if( faceSeeds.empty() ) + BaseType::initEntities( *this, cellSeeds, mesh ); + else + { + BaseType::initEntities( *this, faceSeeds, mesh ); + } } template< int Dimension, int Subdimension > - void initSubentityMatrix( const GlobalIndexType entitiesCount, GlobalIndexType subentitiesCount = 0 ) + void initSubentityMatrix( NeighborCountsArray& capacities, GlobalIndexType subentitiesCount = 0 ) { if( Subdimension == 0 ) subentitiesCount = mesh->template getEntitiesCount< 0 >(); auto& matrix = mesh->template getSubentitiesMatrix< Dimension, Subdimension >(); - matrix.setDimensions( entitiesCount, subentitiesCount ); - using EntityTraitsType = typename MeshTraitsType::template EntityTraits< Dimension >; - using EntityTopology = typename EntityTraitsType::EntityTopology; - using SubentityTraitsType = typename MeshTraitsType::template SubentityTraits< EntityTopology, Subdimension >; - constexpr int count = SubentityTraitsType::count; - typename std::decay_t::RowsCapacitiesType capacities( entitiesCount ); - capacities.setValue( count ); + matrix.setDimensions( capacities.getSize(), subentitiesCount ); matrix.setRowCapacities( capacities ); + initSubentitiesCounts< Dimension, Subdimension >( capacities ); + } + + template< int Dimension, int Subdimension > + void initSubentitiesCounts( const NeighborCountsArray& capacities ) + { + mesh->template setSubentitiesCounts< Dimension, Subdimension >( std::move( capacities ) ); } template< int Dimension > @@ -133,6 +146,22 @@ class Initializer return mesh->template getSubentitiesMatrix< Dimension, 0 >().getRow( entityIndex ); } + template< int Dimension > + auto + getSubverticesCount( const GlobalIndexType entityIndex ) + -> decltype( this->mesh->template getSubentitiesCount< Dimension, 0 >( 0 ) ) + { + return mesh->template getSubentitiesCount< Dimension, 0 >( entityIndex ); + } + + template< int Dimension, int Subdimension > + auto + getSubentitiesMatrix() + -> decltype( this->mesh->template getSubentitiesMatrix< Dimension, Subdimension >() ) + { + return mesh->template getSubentitiesMatrix< Dimension, Subdimension >(); + } + template< int Dimension, int Superdimension > auto getSuperentitiesCountsArray() @@ -148,6 +177,13 @@ class Initializer { return mesh->template getSuperentitiesMatrix< Dimension, Superdimension >(); } + + CellSeedMatrixType& getCellSeeds() + { + return *(this->cellSeeds); + } + protected: + CellSeedMatrixType* cellSeeds = nullptr; }; /**** @@ -158,6 +194,7 @@ class InitializerLayer< MeshConfig, typename MeshTraits< MeshConfig >::Dimension : public InitializerLayer< MeshConfig, typename MeshTraits< MeshConfig >::DimensionTag::Decrement > { +protected: using MeshTraitsType = MeshTraits< MeshConfig >; using DimensionTag = typename MeshTraitsType::DimensionTag; using BaseType = InitializerLayer< MeshConfig, typename DimensionTag::Decrement >; @@ -170,22 +207,27 @@ class InitializerLayer< MeshConfig, typename MeshTraits< MeshConfig >::Dimension using InitializerType = Initializer< MeshConfig >; using EntityInitializerType = EntityInitializer< MeshConfig, EntityTopology >; - using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; + using CellSeedMatrixType = typename MeshTraitsType::CellSeedMatrixType; + using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: - void initEntities( InitializerType& initializer, CellSeedArrayType& cellSeeds, MeshType& mesh ) + void initEntities( InitializerType& initializer, CellSeedMatrixType& cellSeeds, MeshType& mesh ) { //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; - initializer.template setEntitiesCount< DimensionTag::value >( cellSeeds.getSize() ); - initializer.template initSubentityMatrix< DimensionTag::value, 0 >( cellSeeds.getSize() ); - for( GlobalIndexType i = 0; i < cellSeeds.getSize(); i++ ) - EntityInitializerType::initEntity( i, cellSeeds[ i ], initializer ); - cellSeeds.reset(); - + initializer.template setEntitiesCount< DimensionTag::value >( cellSeeds.getEntitiesCount() ); + EntityInitializerType::initSubvertexMatrix( cellSeeds, initializer ); BaseType::initEntities( initializer, mesh ); } + void initEntities( InitializerType& initializer, FaceSeedMatrixType& faceSeeds, MeshType& mesh ) + { + //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; + initializer.template setEntitiesCount< DimensionTag::value >( initializer.getCellSeeds().getEntitiesCount() ); + BaseType::initEntities( initializer, faceSeeds, mesh ); + } + using BaseType::findEntitySeedIndex; }; @@ -198,6 +240,7 @@ class InitializerLayer : public InitializerLayer< MeshConfig, typename DimensionTag::Decrement > { +protected: using BaseType = InitializerLayer< MeshConfig, typename DimensionTag::Decrement >; using MeshType = Mesh< MeshConfig >; using MeshTraitsType = MeshTraits< MeshConfig >; @@ -211,60 +254,74 @@ class InitializerLayer using EntityInitializerType = EntityInitializer< MeshConfig, EntityTopology >; using SeedType = EntitySeed< MeshConfig, EntityTopology >; using SeedIndexedSet = typename MeshTraits< MeshConfig >::template EntityTraits< DimensionTag::value >::SeedIndexedSetType; - using SeedSet = typename MeshTraits< MeshConfig >::template EntityTraits< DimensionTag::value >::SeedSetType; - + using SeedMatrixType = typename EntityTraitsType::SeedMatrixType; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + public: - GlobalIndexType getEntitiesCount( InitializerType& initializer, MeshType& mesh ) + void createSeeds( InitializerType& initializer, MeshType& mesh ) { - using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, Meshes::DimensionTag< MeshType::getMeshDimension() >, DimensionTag >; - SeedSet seedSet; - - for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) - { - auto subentitySeeds = SubentitySeedsCreator::create( initializer.template getSubvertices< MeshType::getMeshDimension() >( i ) ); - for( LocalIndexType j = 0; j < subentitySeeds.getSize(); j++ ) - seedSet.insert( subentitySeeds[ j ] ); + this->seedsIndexedSet.reserve( mesh.template getEntitiesCount< MeshTraitsType::meshDimension >() ); + using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, typename MeshTraitsType::CellTopology, DimensionTag >; + for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) { + SubentitySeedsCreator::iterate( initializer, mesh, i, [&] ( SeedType& seed ) { + this->seedsIndexedSet.insert( std::move( seed ) ); + }); } - - return seedSet.size(); } using BaseType::findEntitySeedIndex; - GlobalIndexType findEntitySeedIndex( const SeedType& seed ) + GlobalIndexType findEntitySeedIndex( const SeedType& seed ) const { - return this->seedsIndexedSet.insert( seed ); + GlobalIndexType index = -1; + this->seedsIndexedSet.find( seed, index ); + return index; } void initEntities( InitializerType& initializer, MeshType& mesh ) { //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; - const GlobalIndexType numberOfEntities = getEntitiesCount( initializer, mesh ); + + // create seeds and set entities count + createSeeds( initializer, mesh ); + const GlobalIndexType numberOfEntities = this->seedsIndexedSet.size(); initializer.template setEntitiesCount< DimensionTag::value >( numberOfEntities ); - EntityInitializerType::initSubvertexMatrix( numberOfEntities, initializer ); - using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, Meshes::DimensionTag< MeshType::getMeshDimension() >, DimensionTag >; - for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) - { - auto subentitySeeds = SubentitySeedsCreator::create( initializer.template getSubvertices< MeshType::getMeshDimension() >( i ) ); - for( LocalIndexType j = 0; j < subentitySeeds.getSize(); j++ ) - { - auto& seed = subentitySeeds[ j ]; - const auto pair = this->seedsIndexedSet.try_insert( seed ); - const GlobalIndexType& entityIndex = pair.first; - if( pair.second ) { - // insertion took place, initialize the entity - EntityInitializerType::initEntity( entityIndex, seed, initializer ); - } - } + // allocate the subvertex matrix + NeighborCountsArray capacities( numberOfEntities ); + for( auto& pair : this->seedsIndexedSet ) { + const auto& seed = pair.first; + const auto& entityIndex = pair.second; + capacities.setElement( entityIndex, seed.getCornersCount() ); } + EntityInitializerType::initSubvertexMatrix( capacities, initializer ); + // initialize the entities + for( auto& pair : this->seedsIndexedSet ) { + const auto& seed = pair.first; + const auto& entityIndex = pair.second; + EntityInitializerType::initEntity( entityIndex, seed, initializer ); + } + + // initialize links between the entities and all superentities EntityInitializerType::initSuperentities( initializer, mesh ); - this->seedsIndexedSet.clear(); + // deallocate the indexed set and continue with the next dimension + this->seedsIndexedSet.clear(); BaseType::initEntities( initializer, mesh ); } + // This overload of initEntities is only called when face seeds are required for initialization. + // Currently only polyhedral meshes use this function. + void initEntities( InitializerType& initializer, SeedMatrixType& seeds, MeshType& mesh ) + { + //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; + initializer.template setEntitiesCount< DimensionTag::value >( seeds.getEntitiesCount() ); + EntityInitializerType::initSubvertexMatrix( seeds, initializer ); + EntityInitializerType::initSuperentities( initializer, mesh ); // initialize links between the entities and all superentities + BaseType::initEntities( initializer, mesh ); // continue with the next dimension + } + private: SeedIndexedSet seedsIndexedSet; }; @@ -276,17 +333,18 @@ template< typename MeshConfig > class InitializerLayer< MeshConfig, DimensionTag< 0 > > { using MeshType = Mesh< MeshConfig >; - using MeshTraitsType = typename MeshType::MeshTraitsType; + using MeshTraitsType = MeshTraits< MeshConfig >; using DimensionTag = Meshes::DimensionTag< 0 >; using EntityTraitsType = typename MeshTraitsType::template EntityTraits< DimensionTag::value >; using EntityTopology = typename EntityTraitsType::EntityTopology; - using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; - using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; using InitializerType = Initializer< MeshConfig >; using EntityInitializerType = EntityInitializer< MeshConfig, EntityTopology >; using SeedType = EntitySeed< MeshConfig, EntityTopology >; + using SeedMatrixType = typename EntityTraitsType::SeedMatrixType; public: @@ -300,6 +358,11 @@ class InitializerLayer< MeshConfig, DimensionTag< 0 > > //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; EntityInitializerType::initSuperentities( initializer, mesh ); } + + // This overload is only here for compatibility with Polyhedrons, it is never called + void initEntities( InitializerType& initializer, SeedMatrixType& faceSeeds, MeshType& mesh ) + { + } }; } // namespace Meshes diff --git a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h index 52dcc73c71aeb3eeff3789bf66173018af81d9ac..b11c7c945b83982ed04967a86695d5d90ee21ae2 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h +++ b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h @@ -18,68 +18,324 @@ #include #include +#include +#include namespace TNL { namespace Meshes { template< typename MeshConfig, - typename EntityDimensionTag, + typename EntityTopology, typename SubentityDimensionTag > class SubentitySeedsCreator { + using MeshType = Mesh< MeshConfig >; using MeshTraitsType = MeshTraits< MeshConfig >; + using InitializerType = Initializer< MeshConfig >; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; - using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityDimensionTag::value >; - using EntityTopology = typename EntityTraitsType::EntityTopology; - using SubvertexAccessorType = typename MeshTraitsType::SubentityMatrixType::RowView; + using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, SubentityDimensionTag::value >; using SubentityTopology = typename SubentityTraits::SubentityTopology; - - static constexpr LocalIndexType SUBENTITY_VERTICES_COUNT = MeshTraitsType::template SubentityTraits< SubentityTopology, 0 >::count; - + public: - using SubentitySeedArray = Containers::StaticArray< SubentityTraits::count, EntitySeed< MeshConfig, SubentityTopology > >; - - static SubentitySeedArray create( const SubvertexAccessorType& subvertices ) + using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; + //using SubentitySeedArray = Containers::StaticArray< SubentityTraits::count, SubentitySeed >; + + /*static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { + const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); + SubentitySeedArray subentitySeeds; Algorithms::staticFor< LocalIndexType, 0, SubentitySeedArray::getSize() >( [&] ( auto subentityIndex ) { - Algorithms::staticFor< LocalIndexType, 0, SUBENTITY_VERTICES_COUNT >( + constexpr LocalIndexType subentityVerticesCount = Topologies::SubentityVertexCount< EntityTopology, SubentityTopology, subentityIndex >::count; + auto& subentitySeed = subentitySeeds[ subentityIndex ]; + subentitySeed.setCornersCount( subentityVerticesCount ); + Algorithms::staticFor< LocalIndexType, 0, subentityVerticesCount >( [&] ( auto subentityVertexIndex ) { // subentityIndex cannot be captured as constexpr, so we need to create another instance of its type static constexpr LocalIndexType VERTEX_INDEX = SubentityTraits::template Vertex< decltype(subentityIndex){}, subentityVertexIndex >::index; - subentitySeeds[ subentityIndex ].setCornerId( subentityVertexIndex, subvertices.getColumnIndex( VERTEX_INDEX ) ); + subentitySeed.setCornerId( subentityVertexIndex, subvertices.getColumnIndex( VERTEX_INDEX ) ); } ); } ); return subentitySeeds; + }*/ + + template< typename FunctorType > + static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) + { + const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); + + Algorithms::staticFor< LocalIndexType, 0, SubentityTraits::count >( + [&] ( auto subentityIndex ) { + constexpr LocalIndexType subentityVerticesCount = Topologies::SubentityVertexCount< EntityTopology, SubentityTopology, subentityIndex >::count; + SubentitySeed subentitySeed; + subentitySeed.setCornersCount( subentityVerticesCount ); + Algorithms::staticFor< LocalIndexType, 0, subentityVerticesCount >( + [&] ( auto subentityVertexIndex ) { + // subentityIndex cannot be captured as constexpr, so we need to create another instance of its type + static constexpr LocalIndexType VERTEX_INDEX = SubentityTraits::template Vertex< decltype(subentityIndex){}, subentityVertexIndex >::index; + subentitySeed.setCornerId( subentityVertexIndex, subvertices.getColumnIndex( VERTEX_INDEX ) ); + } + ); + std::forward< FunctorType >( functor )( subentitySeed ); + } + ); + } + + constexpr static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + return SubentityTraits::count; } }; template< typename MeshConfig, - typename EntityDimensionTag > -class SubentitySeedsCreator< MeshConfig, EntityDimensionTag, DimensionTag< 0 > > + typename EntityTopology > +class SubentitySeedsCreator< MeshConfig, EntityTopology, DimensionTag< 0 > > { + using MeshType = Mesh< MeshConfig >; using MeshTraitsType = MeshTraits< MeshConfig >; + using InitializerType = Initializer< MeshConfig >; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; - using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityDimensionTag::value >; - using EntityTopology = typename EntityTraitsType::EntityTopology; - using SubvertexAccessorType = typename MeshTraitsType::SubentityMatrixType::RowView; + using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 0 >; using SubentityTopology = typename SubentityTraits::SubentityTopology; public: - using SubentitySeedArray = Containers::StaticArray< SubentityTraits::count, EntitySeed< MeshConfig, SubentityTopology > >; + using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; + using SubentitySeedArray = Containers::StaticArray< SubentityTraits::count, SubentitySeed >; - static SubentitySeedArray create( const SubvertexAccessorType& subvertices ) + /*static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { + const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); + SubentitySeedArray seeds; for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) seeds[ i ].setCornerId( 0, subvertices.getColumnIndex( i ) ); return seeds; + }*/ + + template< typename FunctorType > + static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) + { + const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); + + for( LocalIndexType i = 0; i < SubentitySeedArray::getSize(); i++ ) { + SubentitySeed seed; + seed.setCornerId( 0, subvertices.getColumnIndex( i ) ); + std::forward< FunctorType >( functor )( seed ); + } + } + + constexpr static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + return SubentityTraits::count; + } +}; + +template< typename MeshConfig > +class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 1 > > +{ + using MeshType = Mesh< MeshConfig >; + using MeshTraitsType = MeshTraits< MeshConfig >; + using InitializerType = Initializer< MeshConfig >; + using DeviceType = typename MeshTraitsType::DeviceType; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using EntityTopology = Topologies::Polygon; + using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; + using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 1 >; + using SubentityTopology = typename SubentityTraits::SubentityTopology; + +public: + using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; + + template< typename FunctorType > + static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) + { + const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); + const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); + + for( LocalIndexType i = 0; i < subverticesCount; i++ ) + { + SubentitySeed seed; + seed.setCornerId( 0, subvertices.getColumnIndex( i ) ); + seed.setCornerId( 1, subvertices.getColumnIndex( (i + 1) % subverticesCount ) ); + std::forward< FunctorType >( functor )( seed ); + } + } + + static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + return mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); + } +}; + +template< typename MeshConfig > +class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 0 > > +{ + using MeshType = Mesh< MeshConfig >; + using MeshTraitsType = MeshTraits< MeshConfig >; + using InitializerType = Initializer< MeshConfig >; + using DeviceType = typename MeshTraitsType::DeviceType; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using EntityTopology = Topologies::Polygon; + using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; + using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 0 >; + using SubentityTopology = typename SubentityTraits::SubentityTopology; + +public: + using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; + + template< typename FunctorType > + static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) + { + const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); + const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); + + for( LocalIndexType i = 0; i < subverticesCount; i++ ) { + SubentitySeed seed; + seed.setCornerId( 0, subvertices.getColumnIndex( i ) ); + std::forward< FunctorType >( functor )( seed ); + } + } + + static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + return mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); + } +}; + +template< typename MeshConfig > +class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 2 > > +{ + using MeshType = Mesh< MeshConfig >; + using MeshTraitsType = MeshTraits< MeshConfig >; + using InitializerType = Initializer< MeshConfig >; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + +public: + template< typename FunctorType > + static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) + { + throw std::logic_error{ "Subentities of dimension 2 for polyhedrons should be initialized from seeds." }; + } + + static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + throw std::logic_error{ "Subentities of dimension 2 for polyhedrons should be initialized from seeds." }; + } +}; + +template< typename MeshConfig > +class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 1 > > +{ + using MeshType = Mesh< MeshConfig >; + using MeshTraitsType = MeshTraits< MeshConfig >; + using InitializerType = Initializer< MeshConfig >; + using DeviceType = typename MeshTraitsType::DeviceType; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using EntityTopology = Topologies::Polyhedron; + using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; + using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 1 >; + using SubentityTopology = typename SubentityTraits::SubentityTopology; + using SeedSet = typename MeshTraitsType::template EntityTraits< 1 >::SeedSetType; + using FaceSubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 1 > >; + +public: + using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; + + template< typename FunctorType > + static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) + { + SeedSet seedSet; + const auto& faces = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 2 >().getRow( entityIndex ); + const LocalIndexType facesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 2 >( entityIndex ); + + for( LocalIndexType i = 0; i < facesCount; i++ ) { + GlobalIndexType faceIdx = faces.getColumnIndex( i ); + FaceSubentitySeedsCreator::iterate( initializer, mesh, faceIdx, [&] ( SubentitySeed& seed ) { + const bool inserted = seedSet.insert( seed ).second; + if( inserted ) + std::forward< FunctorType >( functor )( seed ); + }); + } + } + + static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + SeedSet seedSet; + const auto& faces = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 2 >().getRow( entityIndex ); + const LocalIndexType facesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 2 >( entityIndex ); + for( LocalIndexType i = 0; i < facesCount; i++ ) { + GlobalIndexType faceIdx = faces.getColumnIndex( i ); + FaceSubentitySeedsCreator::iterate( initializer, mesh, faceIdx, [&] ( SubentitySeed& seed ) { + seedSet.insert( seed ); + }); + } + + return seedSet.size(); + } +}; + +template< typename MeshConfig > +class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 0 > > +{ + using MeshType = Mesh< MeshConfig >; + using MeshTraitsType = MeshTraits< MeshConfig >; + using InitializerType = Initializer< MeshConfig >; + using DeviceType = typename MeshTraitsType::DeviceType; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using EntityTopology = Topologies::Polyhedron; + using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; + using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 0 >; + using SubentityTopology = typename SubentityTraits::SubentityTopology; + using SeedSet = typename MeshTraitsType::template EntityTraits< 0 >::SeedSetType; + using FaceSubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 0 > >; + +public: + using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; + + template< typename FunctorType > + static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) + { + SeedSet seedSet; + const auto& faces = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 2 >().getRow( entityIndex ); + const LocalIndexType facesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 2 >( entityIndex ); + + for( LocalIndexType i = 0; i < facesCount; i++ ) { + GlobalIndexType faceIdx = faces.getColumnIndex( i ); + FaceSubentitySeedsCreator::iterate( initializer, mesh, faceIdx, [&] ( SubentitySeed& seed ) { + const bool inserted = seedSet.insert( seed ).second; + if( inserted ) + std::forward< FunctorType >( functor )( seed ); + }); + } + } + + static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + SeedSet seedSet; + const auto& faces = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 2 >().getRow( entityIndex ); + const LocalIndexType facesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 2 >( entityIndex ); + + for( LocalIndexType i = 0; i < facesCount; i++ ) { + GlobalIndexType faceIdx = faces.getColumnIndex( i ); + FaceSubentitySeedsCreator::iterate( initializer, mesh, faceIdx, [&] ( SubentitySeed& seed ) { + seedSet.insert( seed ); + }); + } + + return seedSet.size(); } }; diff --git a/src/TNL/Meshes/MeshDetails/layers/DualGraphLayer.h b/src/TNL/Meshes/MeshDetails/layers/DualGraphLayer.h index 3ca05fc00c6bab76f8ba982268107a611fa889c5..0292ccd53ecc4be72964e54c8149e72d7fce274c 100644 --- a/src/TNL/Meshes/MeshDetails/layers/DualGraphLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/DualGraphLayer.h @@ -33,6 +33,8 @@ public: explicit DualGraphLayer( const DualGraphLayer& ) = default; + DualGraphLayer( DualGraphLayer&& ) = default; + template< typename Device_ > DualGraphLayer( const DualGraphLayer< MeshConfig, Device_ >& other ) { @@ -41,6 +43,8 @@ public: DualGraphLayer& operator=( const DualGraphLayer& ) = default; + DualGraphLayer& operator=( DualGraphLayer&& ) = default; + template< typename Device_ > DualGraphLayer& operator=( const DualGraphLayer< MeshConfig, Device_ >& other ) { @@ -167,11 +171,6 @@ template< typename MeshConfig, class DualGraphLayer< MeshConfig, Device, false > { public: - DualGraphLayer& operator=( const DualGraphLayer& other ) - { - return *this; - } - template< typename Device_ > DualGraphLayer& operator=( const DualGraphLayer< MeshConfig, Device_ >& other ) { diff --git a/src/TNL/Meshes/MeshDetails/layers/EntityTags/Layer.h b/src/TNL/Meshes/MeshDetails/layers/EntityTags/Layer.h index b722535a516726ef40727ea77053885d311dff62..985541c1bb67db28804c59d959f27a2878643fea 100644 --- a/src/TNL/Meshes/MeshDetails/layers/EntityTags/Layer.h +++ b/src/TNL/Meshes/MeshDetails/layers/EntityTags/Layer.h @@ -38,10 +38,7 @@ public: Layer() = default; - explicit Layer( const Layer& other ) - { - operator=( other ); - } + explicit Layer( const Layer& other ) = default; template< typename Device_ > Layer( const Layer< MeshConfig, Device_, DimensionTag >& other ) @@ -49,24 +46,13 @@ public: operator=( other ); } - Layer& operator=( const Layer& other ) - { - tags.setLike( other.tags ); - boundaryIndices.setLike( other.boundaryIndices ); - interiorIndices.setLike( other.interiorIndices ); - tags = other.tags; - boundaryIndices = other.boundaryIndices; - interiorIndices = other.interiorIndices; - ghostsOffset = other.ghostsOffset; - return *this; - } + Layer& operator=( const Layer& other ) = default; + + Layer& operator=( Layer&& other ) = default; template< typename Device_ > Layer& operator=( const Layer< MeshConfig, Device_, DimensionTag >& other ) { - tags.setLike( other.tags ); - boundaryIndices.setLike( other.boundaryIndices ); - interiorIndices.setLike( other.interiorIndices ); tags = other.tags; boundaryIndices = other.boundaryIndices; interiorIndices = other.interiorIndices; @@ -254,10 +240,12 @@ protected: using TagType = typename MeshTraits< MeshConfig, Device >::EntityTagsArrayType::ValueType; Layer() = default; - explicit Layer( const Layer& other ) {} + explicit Layer( const Layer& other ) = default; + Layer( Layer&& other ) = default; template< typename Device_ > Layer( const Layer< MeshConfig, Device_, DimensionTag >& other ) {} - Layer& operator=( const Layer& other ) { return *this; } + Layer& operator=( const Layer& other ) = default; + Layer& operator=( Layer&& other ) = default; template< typename Device_ > Layer& operator=( const Layer< MeshConfig, Device_, DimensionTag >& other ) { return *this; } diff --git a/src/TNL/Meshes/MeshDetails/layers/EntityTags/LayerFamily.h b/src/TNL/Meshes/MeshDetails/layers/EntityTags/LayerFamily.h index 712bee34ee5fb05b0f6952d25e4661a7b186c546..de0bac7c64a33ec07eceb629694013ad32811e29 100644 --- a/src/TNL/Meshes/MeshDetails/layers/EntityTags/LayerFamily.h +++ b/src/TNL/Meshes/MeshDetails/layers/EntityTags/LayerFamily.h @@ -56,10 +56,9 @@ protected: LayerInheritor() = default; - explicit LayerInheritor( const LayerInheritor& other ) - { - operator=( other ); - } + explicit LayerInheritor( const LayerInheritor& other ) = default; + + LayerInheritor( LayerInheritor&& other ) = default; template< typename Device_ > LayerInheritor( const LayerInheritor< MeshConfig, Device_, Dimension >& other ) @@ -67,12 +66,9 @@ protected: operator=( other ); } - LayerInheritor& operator=( const LayerInheritor& other ) - { - LayerType::operator=( other ); - BaseType::operator=( other ); - return *this; - } + LayerInheritor& operator=( const LayerInheritor& other ) = default; + + LayerInheritor& operator=( LayerInheritor&& other ) = default; template< typename Device_ > LayerInheritor& operator=( const LayerInheritor< MeshConfig, Device_, Dimension >& other ) @@ -114,10 +110,12 @@ protected: void getGhostEntitiesOffset() const; LayerInheritor() = default; - explicit LayerInheritor( const LayerInheritor& other ) {} + explicit LayerInheritor( const LayerInheritor& other ) = default; + LayerInheritor( LayerInheritor&& other ) = default; template< typename Device_ > LayerInheritor( const LayerInheritor< MeshConfig, Device_, DimensionTag< MeshConfig::meshDimension + 1 > >& other ) {} - LayerInheritor& operator=( const LayerInheritor& other ) { return *this; } + LayerInheritor& operator=( const LayerInheritor& other ) = default; + LayerInheritor& operator=( LayerInheritor&& other ) = default; template< typename Device_ > LayerInheritor& operator=( const LayerInheritor< MeshConfig, Device_, DimensionTag< MeshConfig::meshDimension + 1 > >& other ) { return *this; } diff --git a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h index 38bddd6578a361a4c98069b5df20615f61f96b84..6d88caaa6beaf42793753cc859297cde4c300378 100644 --- a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h @@ -38,6 +38,7 @@ class StorageLayerFamily public DualGraphLayer< MeshConfig, Device > { using MeshTraitsType = MeshTraits< MeshConfig, Device >; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using BaseType = StorageLayer< MeshConfig, Device, DimensionTag< 0 > >; template< int Dimension > using EntityTraits = typename MeshTraitsType::template EntityTraits< Dimension >; @@ -48,16 +49,12 @@ class StorageLayerFamily template< int Dimension, int Superdimension > using SuperentityTraits = typename MeshTraitsType::template SuperentityTraits< typename EntityTraits< Dimension >::EntityTopology, Superdimension >; -protected: - typename MeshTraitsType::PointArrayType points; - public: StorageLayerFamily() = default; - explicit StorageLayerFamily( const StorageLayerFamily& other ) - { - operator=( other ); - } + explicit StorageLayerFamily( const StorageLayerFamily& other ) = default; + + StorageLayerFamily( StorageLayerFamily&& other ) = default; template< typename Device_ > StorageLayerFamily( const StorageLayerFamily< MeshConfig, Device_ >& other ) @@ -65,18 +62,13 @@ public: operator=( other ); } - StorageLayerFamily& operator=( const StorageLayerFamily& layer ) - { - points = layer.getPoints(); - BaseType::operator=( layer ); - DualGraphLayer< MeshConfig, Device >::operator=( layer ); - return *this; - } + StorageLayerFamily& operator=( const StorageLayerFamily& layer ) = default; + + StorageLayerFamily& operator=( StorageLayerFamily&& layer ) = default; template< typename Device_ > StorageLayerFamily& operator=( const StorageLayerFamily< MeshConfig, Device_ >& layer ) { - points = layer.getPoints(); BaseType::operator=( layer ); DualGraphLayer< MeshConfig, Device >::operator=( layer ); return *this; @@ -84,74 +76,62 @@ public: bool operator==( const StorageLayerFamily& layer ) const { - return ( points == layer.points && - BaseType::operator==( layer ) && + return ( BaseType::operator==( layer ) && DualGraphLayer< MeshConfig, Device >::operator==( layer ) ); } - void print( std::ostream& str ) const - { - str << "Vertex coordinates are: " << points << std::endl; - BaseType::print( str ); - } - - const typename MeshTraitsType::PointArrayType& getPoints() const - { - return points; - } - - typename MeshTraitsType::PointArrayType& getPoints() - { - return points; - } - - template< int Dimension > - void setEntitiesCount( const typename MeshTraitsType::GlobalIndexType& entitiesCount ) + template< int Dimension, int Subdimension > + void + setSubentitiesCounts( const typename MeshTraitsType::NeighborCountsArray& counts ) { - BaseType::setEntitiesCount( DimensionTag< Dimension >(), entitiesCount ); - if( Dimension == 0 ) - points.setSize( entitiesCount ); + static_assert( Dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); + static_assert( SubentityTraits< Dimension, Subdimension >::storageEnabled, + "You try to set subentitiesCounts for a combination of Dimension and Subdimension which is disabled in the mesh configuration." ); + using BaseType = SubentityStorageLayerFamily< MeshConfig, + Device, + typename EntityTraits< Dimension >::EntityTopology >; + BaseType::template setSubentitiesCounts< Subdimension >( counts ); } template< int Dimension, int Subdimension > __cuda_callable__ typename MeshTraitsType::LocalIndexType - getSubentitiesCount() const + getSubentitiesCount( const GlobalIndexType entityIndex ) const { static_assert( Dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); static_assert( SubentityTraits< Dimension, Subdimension >::storageEnabled, "You try to get subentities count for subentities which are disabled in the mesh configuration." ); using BaseType = SubentityStorageLayerFamily< MeshConfig, - Device, - typename EntityTraits< Dimension >::EntityTopology >; - return BaseType::template getSubentitiesCount< Subdimension >(); + Device, + typename EntityTraits< Dimension >::EntityTopology >; + return BaseType::template getSubentitiesCount< Subdimension >( entityIndex ); } template< int Dimension, int Subdimension > __cuda_callable__ - typename MeshTraitsType::SubentityMatrixType& + typename MeshTraitsType::template SubentityMatrixType< Dimension >& getSubentitiesMatrix() { static_assert( Dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); static_assert( SubentityTraits< Dimension, Subdimension >::storageEnabled, "You try to get subentities matrix which is disabled in the mesh configuration." ); using BaseType = SubentityStorageLayerFamily< MeshConfig, - Device, - typename EntityTraits< Dimension >::EntityTopology >; + Device, + typename EntityTraits< Dimension >::EntityTopology >; return BaseType::template getSubentitiesMatrix< Subdimension >(); } template< int Dimension, int Subdimension > __cuda_callable__ - const typename MeshTraitsType::SubentityMatrixType& + const typename MeshTraitsType::template SubentityMatrixType< Dimension >& getSubentitiesMatrix() const { static_assert( Dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); static_assert( SubentityTraits< Dimension, Subdimension >::storageEnabled, "You try to get subentities matrix which is disabled in the mesh configuration." ); using BaseType = SubentityStorageLayerFamily< MeshConfig, - Device, - typename EntityTraits< Dimension >::EntityTopology >; + Device, + typename EntityTraits< Dimension >::EntityTopology >; return BaseType::template getSubentitiesMatrix< Subdimension >(); } @@ -165,7 +145,7 @@ public: "You try to get superentities counts array which is disabled in the mesh configuration." ); using BaseType = SuperentityStorageLayerFamily< MeshConfig, Device, - typename EntityTraits< Dimension >::EntityTopology >; + DimensionTag< Dimension > >; return BaseType::template getSuperentitiesCountsArray< Superdimension >(); } @@ -179,7 +159,7 @@ public: "You try to get superentities counts array which is disabled in the mesh configuration." ); using BaseType = SuperentityStorageLayerFamily< MeshConfig, Device, - typename EntityTraits< Dimension >::EntityTopology >; + DimensionTag< Dimension > >; return BaseType::template getSuperentitiesCountsArray< Superdimension >(); } @@ -193,7 +173,7 @@ public: "You try to get superentities matrix which is disabled in the mesh configuration." ); using BaseType = SuperentityStorageLayerFamily< MeshConfig, Device, - typename EntityTraits< Dimension >::EntityTopology >; + DimensionTag< Dimension > >; return BaseType::template getSuperentitiesMatrix< Superdimension >(); } @@ -207,7 +187,7 @@ public: "You try to get superentities matrix which is disabled in the mesh configuration." ); using BaseType = SuperentityStorageLayerFamily< MeshConfig, Device, - typename EntityTraits< Dimension >::EntityTopology >; + DimensionTag< Dimension > >; return BaseType::template getSuperentitiesMatrix< Superdimension >(); } }; @@ -225,7 +205,7 @@ class StorageLayer< MeshConfig, typename MeshTraits< MeshConfig, Device >::template EntityTraits< DimensionTag::value >::EntityTopology >, public SuperentityStorageLayerFamily< MeshConfig, Device, - typename MeshTraits< MeshConfig, Device >::template EntityTraits< DimensionTag::value >::EntityTopology >, + DimensionTag >, public StorageLayer< MeshConfig, Device, typename DimensionTag::Increment > { public: @@ -236,14 +216,11 @@ public: using EntityType = typename EntityTraitsType::EntityType; using EntityTopology = typename EntityTraitsType::EntityTopology; using SubentityStorageBaseType = SubentityStorageLayerFamily< MeshConfig, Device, EntityTopology >; - using SuperentityStorageBaseType = SuperentityStorageLayerFamily< MeshConfig, Device, EntityTopology >; + using SuperentityStorageBaseType = SuperentityStorageLayerFamily< MeshConfig, Device, DimensionTag >; StorageLayer() = default; - explicit StorageLayer( const StorageLayer& other ) - { - operator=( other ); - } + explicit StorageLayer( const StorageLayer& other ) = default; template< typename Device_ > StorageLayer( const StorageLayer< MeshConfig, Device_, DimensionTag >& other ) @@ -251,14 +228,9 @@ public: operator=( other ); } - StorageLayer& operator=( const StorageLayer& other ) - { - entitiesCount = other.entitiesCount; - SubentityStorageBaseType::operator=( other ); - SuperentityStorageBaseType::operator=( other ); - BaseType::operator=( other ); - return *this; - } + StorageLayer& operator=( const StorageLayer& other ) = default; + + StorageLayer& operator=( StorageLayer&& other ) = default; template< typename Device_ > StorageLayer& operator=( const StorageLayer< MeshConfig, Device_, DimensionTag >& other ) @@ -319,15 +291,16 @@ protected: StorageLayer() = default; - explicit StorageLayer( const StorageLayer& other ) {} + explicit StorageLayer( const StorageLayer& other ) = default; + + StorageLayer( StorageLayer&& other ) = default; template< typename Device_ > StorageLayer( const StorageLayer< MeshConfig, Device_, DimensionTag >& other ) {} - StorageLayer& operator=( const StorageLayer& other ) - { - return *this; - } + StorageLayer& operator=( const StorageLayer& other ) = default; + + StorageLayer& operator=( StorageLayer&& other ) = default; template< typename Device_ > StorageLayer& operator=( const StorageLayer< MeshConfig, Device_, DimensionTag >& other ) diff --git a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h index 5aa1ee57960b0c0e26a03986b6cc139403fff59a..0cefa9d15db6129c11a49b9fee2693b17c40a903 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -28,7 +28,8 @@ template< typename MeshConfig, typename Device, typename EntityTopology, typename SubdimensionTag, - bool SubentityStorage = WeakSubentityStorageTrait< MeshConfig, Device, EntityTopology, SubdimensionTag >::storageEnabled > + bool SubentityStorage = WeakSubentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopology::dimension >::EntityTopology, SubdimensionTag >::storageEnabled, + bool IsDynamicTopology = Topologies::IsDynamicTopology< EntityTopology >::value > class SubentityStorageLayer; template< typename MeshConfig, @@ -39,6 +40,7 @@ class SubentityStorageLayerFamily { using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, DimensionTag< 0 > >; using MeshTraitsType = MeshTraits< MeshConfig, Device >; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; public: // inherit constructors and assignment operators (including templated versions) @@ -46,18 +48,34 @@ public: using BaseType::operator=; protected: + template< int Subdimension > + void + setSubentitiesCounts( const typename MeshTraitsType::NeighborCountsArray& counts ) + { + static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); + BaseType::setSubentitiesCounts( DimensionTag< Subdimension >( ), counts ); + } + + template< int Subdimension > + void + setSubentitiesCounts( typename MeshTraitsType::NeighborCountsArray&& counts ) + { + static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); + BaseType::setSubentitiesCounts( DimensionTag< Subdimension >( ), std::move( counts ) ); + } + template< int Subdimension > __cuda_callable__ typename MeshTraitsType::LocalIndexType - getSubentitiesCount() const + getSubentitiesCount( const GlobalIndexType entityIndex ) const { static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); - return BaseType::getSubentitiesCount( DimensionTag< Subdimension >() ); + return BaseType::getSubentitiesCount( DimensionTag< Subdimension >( ), entityIndex ); } template< int Subdimension > __cuda_callable__ - typename MeshTraitsType::SubentityMatrixType& + typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >& getSubentitiesMatrix() { static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); @@ -66,7 +84,7 @@ protected: template< int Subdimension > __cuda_callable__ - const typename MeshTraitsType::SubentityMatrixType& + const typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >& getSubentitiesMatrix() const { static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); @@ -74,6 +92,12 @@ protected: } }; +/**** + * Mesh subentity storage layer with specializations + * + * SUBENTITY STORAGE DYNAMIC TOPOLOGY + * TRUE FALSE + */ template< typename MeshConfig, typename Device, typename EntityTopology, @@ -82,7 +106,8 @@ class SubentityStorageLayer< MeshConfig, Device, EntityTopology, SubdimensionTag, - true > + true, + false > : public SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment > { using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment >; @@ -91,37 +116,254 @@ class SubentityStorageLayer< MeshConfig, protected: using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; - using SubentityMatrixType = typename MeshTraitsType::SubentityMatrixType; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; SubentityStorageLayer() = default; - explicit SubentityStorageLayer( const SubentityStorageLayer& other ) + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer( SubentityStorageLayer&& other ) = default; + + template< typename Device_ > + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { operator=( other ); } + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer& operator=( SubentityStorageLayer&& other ) = default; + + template< typename Device_ > + SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) + { + BaseType::operator=( other ); + matrix = other.matrix; + return *this; + } + + void print( std::ostream& str ) const + { + BaseType::print( str ); + str << "Adjacency matrix for subentities with dimension " << SubdimensionTag::value << " of entities with dimension " << EntityTopology::dimension << " is: " << std::endl; + str << matrix << std::endl; + } + + bool operator==( const SubentityStorageLayer& layer ) const + { + return ( BaseType::operator==( layer ) && + matrix == layer.matrix ); + } + +protected: + using BaseType::setSubentitiesCounts; + void setSubentitiesCounts( SubdimensionTag, const typename MeshTraitsType::NeighborCountsArray& counts ) + {} + + void setSubentitiesCounts( SubdimensionTag, typename MeshTraitsType::NeighborCountsArray&& counts ) + {} + + using BaseType::getSubentitiesCount; + __cuda_callable__ + LocalIndexType getSubentitiesCount( SubdimensionTag, const GlobalIndexType entityIndex ) const + { + using SubentityTraitsType = typename MeshTraitsType::template SubentityTraits< EntityTopology, SubdimensionTag::value >; + return SubentityTraitsType::count; + } + + using BaseType::getSubentitiesMatrix; + __cuda_callable__ + SubentityMatrixType& getSubentitiesMatrix( SubdimensionTag ) + { + return matrix; + } + + __cuda_callable__ + const SubentityMatrixType& getSubentitiesMatrix( SubdimensionTag ) const + { + return matrix; + } + +private: + SubentityMatrixType matrix; + + // friend class is needed for templated assignment operators + template< typename MeshConfig_, typename Device_, typename EntityTopology_, typename SubdimensionTag_, bool Storage_, bool dynamicTopology_ > + friend class SubentityStorageLayer; +}; + +/**** + * Mesh subentity storage layer with specializations + * + * SUBENTITY STORAGE DYNAMIC TOPOLOGY + * TRUE TRUE + */ +template< typename MeshConfig, + typename Device, + typename EntityTopology, + typename SubdimensionTag > +class SubentityStorageLayer< MeshConfig, + Device, + EntityTopology, + SubdimensionTag, + true, + true > + : public SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment > +{ + using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment >; + using MeshTraitsType = MeshTraits< MeshConfig, Device >; + +protected: + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; + + SubentityStorageLayer() = default; + + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer( SubentityStorageLayer&& other ) = default; + template< typename Device_ > SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { operator=( other ); } - SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer& operator=( SubentityStorageLayer&& other ) = default; + + template< typename Device_ > + SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { BaseType::operator=( other ); + subentitiesCounts = other.subentitiesCounts; matrix = other.matrix; return *this; } + void save( File& file ) const + { + BaseType::save( file ); + matrix.save( file ); + } + + void load( File& file ) + { + BaseType::load( file ); + matrix.load( file ); + matrix.getCompressedRowLengths( subentitiesCounts ); + } + + void print( std::ostream& str ) const + { + BaseType::print( str ); + str << "Adjacency matrix for subentities with dimension " << SubdimensionTag::value << " of entities with dimension " << EntityTopology::dimension << " is: " << std::endl; + str << matrix << std::endl; + } + + bool operator==( const SubentityStorageLayer& layer ) const + { + return ( BaseType::operator==( layer ) && + subentitiesCounts == layer.subentitiesCounts && + matrix == layer.matrix ); + } + +protected: + using BaseType::setSubentitiesCounts; + void setSubentitiesCounts( SubdimensionTag, const NeighborCountsArray& counts ) + { + subentitiesCounts = counts; + } + + void setSubentitiesCounts( SubdimensionTag, NeighborCountsArray&& counts ) + { + subentitiesCounts = std::move( counts ); + } + + using BaseType::getSubentitiesCount; + __cuda_callable__ + LocalIndexType getSubentitiesCount( SubdimensionTag, const GlobalIndexType entityIndex ) const + { + return subentitiesCounts[ entityIndex ]; + } + + using BaseType::getSubentitiesMatrix; + __cuda_callable__ + SubentityMatrixType& getSubentitiesMatrix( SubdimensionTag ) + { + return matrix; + } + + __cuda_callable__ + const SubentityMatrixType& getSubentitiesMatrix( SubdimensionTag ) const + { + return matrix; + } + +private: + NeighborCountsArray subentitiesCounts; + SubentityMatrixType matrix; + + // friend class is needed for templated assignment operators + template< typename MeshConfig_, typename Device_, typename EntityTopology_, typename SubdimensionTag_, bool Storage_, bool dynamicTopology_ > + friend class SubentityStorageLayer; +}; + +/**** + * Mesh subentity storage layer with specializations + * + * SUBENTITY STORAGE DYNAMIC TOPOLOGY TOPOLOGY Subdimension + * TRUE TRUE Polygon 0 + */ +template< typename MeshConfig, + typename Device > +class SubentityStorageLayer< MeshConfig, + Device, + Topologies::Polygon, + DimensionTag< 0 >, + true, + true > + : public SubentityStorageLayer< MeshConfig, Device, Topologies::Polygon, typename DimensionTag< 0 >::Increment > +{ + using EntityTopology = Topologies::Polygon; + using SubdimensionTag = DimensionTag< 0 >; + using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment >; + using MeshTraitsType = MeshTraits< MeshConfig, Device >; + +protected: + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; + + SubentityStorageLayer() = default; + + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer( SubentityStorageLayer&& other ) = default; + + template< typename Device_ > + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) + { + operator=( other ); + } + + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer& operator=( SubentityStorageLayer&& other ) = default; + template< typename Device_ > SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { BaseType::operator=( other ); + subentitiesCounts = other.subentitiesCounts; matrix = other.matrix; return *this; } - void print( std::ostream& str ) const { BaseType::print( str ); @@ -132,16 +374,34 @@ protected: bool operator==( const SubentityStorageLayer& layer ) const { return ( BaseType::operator==( layer ) && + subentitiesCounts == layer.subentitiesCounts && matrix == layer.matrix ); } protected: + using BaseType::setSubentitiesCounts; + void setSubentitiesCounts( SubdimensionTag, const NeighborCountsArray& counts ) + { + subentitiesCounts = counts; + } + + void setSubentitiesCounts( SubdimensionTag, NeighborCountsArray&& counts ) + { + subentitiesCounts = std::move( counts ); + } + using BaseType::getSubentitiesCount; __cuda_callable__ - LocalIndexType getSubentitiesCount( SubdimensionTag ) const + LocalIndexType getSubentitiesCount( SubdimensionTag, const GlobalIndexType entityIndex ) const { - using SubentityTraitsType = typename MeshTraitsType::template SubentityTraits< EntityTopology, SubdimensionTag::value >; - return SubentityTraitsType::count; + return subentitiesCounts[ entityIndex ]; + } + + // Subdimension 1 has identical subentitiesCounts as Subdimension 0 + __cuda_callable__ + LocalIndexType getSubentitiesCount( typename SubdimensionTag::Increment, const GlobalIndexType entityIndex ) const + { + return subentitiesCounts[ entityIndex ]; } using BaseType::getSubentitiesMatrix; @@ -158,22 +418,126 @@ protected: } private: + NeighborCountsArray subentitiesCounts; SubentityMatrixType matrix; // friend class is needed for templated assignment operators - template< typename MeshConfig_, typename Device_, typename EntityTopology_, typename SubdimensionTag_, bool Storage_ > + template< typename MeshConfig_, typename Device_, typename EntityTopology_, typename SubdimensionTag_, bool Storage_, bool dynamicTopology_ > friend class SubentityStorageLayer; }; +/**** + * Mesh subentity storage layer with specializations + * + * SUBENTITY STORAGE DYNAMIC TOPOLOGY TOPOLOGY Subdimension + * TRUE TRUE Polygon 1 + */ +template< typename MeshConfig, + typename Device > +class SubentityStorageLayer< MeshConfig, + Device, + Topologies::Polygon, + DimensionTag< 1 >, + true, + true > + : public SubentityStorageLayer< MeshConfig, Device, Topologies::Polygon, typename DimensionTag< 1 >::Increment > +{ + using EntityTopology = Topologies::Polygon; + using SubdimensionTag = DimensionTag< 1 >; + using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment >; + using MeshTraitsType = MeshTraits< MeshConfig, Device >; + +protected: + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; + + SubentityStorageLayer() = default; + + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer( SubentityStorageLayer&& other ) = default; + + template< typename Device_ > + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) + { + operator=( other ); + } + + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer& operator=( SubentityStorageLayer&& other ) = default; + + template< typename Device_ > + SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) + { + BaseType::operator=( other ); + matrix = other.matrix; + return *this; + } + + void print( std::ostream& str ) const + { + BaseType::print( str ); + str << "Adjacency matrix for subentities with dimension " << SubdimensionTag::value << " of entities with dimension " << EntityTopology::dimension << " is: " << std::endl; + str << matrix << std::endl; + } + + bool operator==( const SubentityStorageLayer& layer ) const + { + return ( BaseType::operator==( layer ) && + matrix == layer.matrix ); + } + +protected: + using BaseType::setSubentitiesCounts; + void setSubentitiesCounts( SubdimensionTag, const NeighborCountsArray& counts ) + {} + + void setSubentitiesCounts( SubdimensionTag, NeighborCountsArray&& counts ) + {} + + // getSubentitiesCount for subdimension 1 is defined in the specialization for subdimension 0 + + using BaseType::getSubentitiesMatrix; + __cuda_callable__ + SubentityMatrixType& getSubentitiesMatrix( SubdimensionTag ) + { + return matrix; + } + + __cuda_callable__ + const SubentityMatrixType& getSubentitiesMatrix( SubdimensionTag ) const + { + return matrix; + } + +private: + SubentityMatrixType matrix; + + // friend class is needed for templated assignment operators + template< typename MeshConfig_, typename Device_, typename EntityTopology_, typename SubdimensionTag_, bool Storage_, bool dynamicTopology_ > + friend class SubentityStorageLayer; +}; + +/**** + * Mesh subentity storage layer with specializations + * + * SUBENTITY STORAGE DYNAMIC TOPOLOGY + * FALSE TRUE/FALSE + */ template< typename MeshConfig, typename Device, typename EntityTopology, - typename SubdimensionTag > + typename SubdimensionTag, + bool dynamicTopology > class SubentityStorageLayer< MeshConfig, Device, EntityTopology, SubdimensionTag, - false > + false, + dynamicTopology > : public SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment > { using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment >; @@ -186,22 +550,28 @@ public: // termination of recursive inheritance (everything is reduced to EntityStorage == false thanks to the WeakSubentityStorageTrait) template< typename MeshConfig, typename Device, - typename EntityTopology > + typename EntityTopology, + bool dynamicTopology > class SubentityStorageLayer< MeshConfig, Device, EntityTopology, DimensionTag< EntityTopology::dimension >, - false > + false, + dynamicTopology > { + using MeshTraitsType = MeshTraits< MeshConfig, Device >; using SubdimensionTag = DimensionTag< EntityTopology::dimension >; protected: using GlobalIndexType = typename MeshConfig::GlobalIndexType; SubentityStorageLayer() = default; - explicit SubentityStorageLayer( const SubentityStorageLayer& other ) {} + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) = default; + SubentityStorageLayer( SubentityStorageLayer&& other ) = default; template< typename Device_ > SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) {} + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) = default; + SubentityStorageLayer& operator=( SubentityStorageLayer&& other ) = default; template< typename Device_ > SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { return *this; } @@ -212,6 +582,8 @@ protected: return true; } + void setSubentitiesCounts( SubdimensionTag, const typename MeshTraitsType::NeighborCountsArray& ); + void setSubentitiesCounts( SubdimensionTag, typename MeshTraitsType::NeighborCountsArray&& ); void getSubentitiesCount( SubdimensionTag ) {} void getSubentitiesMatrix( SubdimensionTag ) {} }; diff --git a/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h index 3cd6a5a2963de03c035652a171d9b462aa20490a..5a802735c8850939b5a13b92f214d158a1d487a2 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h @@ -26,23 +26,23 @@ namespace Meshes { template< typename MeshConfig, typename Device, - typename EntityTopology, + typename EntityDimensionTag, typename SuperdimensionTag, - bool SuperentityStorage = WeakSuperentityStorageTrait< MeshConfig, Device, EntityTopology, SuperdimensionTag >::storageEnabled > + bool SuperentityStorage = WeakSuperentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityDimensionTag::value >::EntityTopology, SuperdimensionTag >::storageEnabled > class SuperentityStorageLayer; template< typename MeshConfig, typename Device, - typename EntityTopology > + typename EntityDimensionTag > class SuperentityStorageLayerFamily : public SuperentityStorageLayer< MeshConfig, Device, - EntityTopology, + EntityDimensionTag, DimensionTag< MeshTraits< MeshConfig, Device >::meshDimension > > { using BaseType = SuperentityStorageLayer< MeshConfig, Device, - EntityTopology, + EntityDimensionTag, DimensionTag< MeshTraits< MeshConfig, Device >::meshDimension > >; using MeshTraitsType = MeshTraits< MeshConfig, Device >; @@ -57,7 +57,7 @@ protected: typename MeshTraitsType::NeighborCountsArray& getSuperentitiesCountsArray() { - static_assert( EntityTopology::dimension < Superdimension, "Invalid combination of Dimension and Superdimension." ); + static_assert( EntityDimensionTag::value < Superdimension, "Invalid combination of Dimension and Superdimension." ); return BaseType::getSuperentitiesCountsArray( DimensionTag< Superdimension >() ); } @@ -66,7 +66,7 @@ protected: const typename MeshTraitsType::NeighborCountsArray& getSuperentitiesCountsArray() const { - static_assert( EntityTopology::dimension < Superdimension, "Invalid combination of Dimension and Superdimension." ); + static_assert( EntityDimensionTag::value < Superdimension, "Invalid combination of Dimension and Superdimension." ); return BaseType::getSuperentitiesCountsArray( DimensionTag< Superdimension >() ); } @@ -75,7 +75,7 @@ protected: typename MeshTraitsType::SuperentityMatrixType& getSuperentitiesMatrix() { - static_assert( EntityTopology::dimension < Superdimension, "Invalid combination of Dimension and Superdimension." ); + static_assert( EntityDimensionTag::value < Superdimension, "Invalid combination of Dimension and Superdimension." ); return BaseType::getSuperentitiesMatrix( DimensionTag< Superdimension >() ); } @@ -84,19 +84,19 @@ protected: const typename MeshTraitsType::SuperentityMatrixType& getSuperentitiesMatrix() const { - static_assert( EntityTopology::dimension < Superdimension, "Invalid combination of Dimension and Superdimension." ); + static_assert( EntityDimensionTag::value < Superdimension, "Invalid combination of Dimension and Superdimension." ); return BaseType::getSuperentitiesMatrix( DimensionTag< Superdimension >() ); } }; template< typename MeshConfig, typename Device, - typename EntityTopology, + typename EntityDimensionTag, typename SuperdimensionTag > -class SuperentityStorageLayer< MeshConfig, Device, EntityTopology, SuperdimensionTag, true > - : public SuperentityStorageLayer< MeshConfig, Device, EntityTopology, typename SuperdimensionTag::Decrement > +class SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, SuperdimensionTag, true > + : public SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, typename SuperdimensionTag::Decrement > { - using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityTopology, typename SuperdimensionTag::Decrement >; + using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, typename SuperdimensionTag::Decrement >; using MeshTraitsType = MeshTraits< MeshConfig, Device >; protected: @@ -105,27 +105,22 @@ protected: SuperentityStorageLayer() = default; - explicit SuperentityStorageLayer( const SuperentityStorageLayer& other ) - { - operator=( other ); - } + explicit SuperentityStorageLayer( const SuperentityStorageLayer& other ) = default; + + SuperentityStorageLayer( SuperentityStorageLayer&& other ) = default; template< typename Device_ > - SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopology, SuperdimensionTag >& other ) + SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityDimensionTag, SuperdimensionTag >& other ) { operator=( other ); } - SuperentityStorageLayer& operator=( const SuperentityStorageLayer& other ) - { - BaseType::operator=( other ); - superentitiesCounts = other.superentitiesCounts; - matrix = other.matrix; - return *this; - } + SuperentityStorageLayer& operator=( const SuperentityStorageLayer& other ) = default; + + SuperentityStorageLayer& operator=( SuperentityStorageLayer&& other ) = default; template< typename Device_ > - SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopology, SuperdimensionTag >& other ) + SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityDimensionTag, SuperdimensionTag >& other ) { BaseType::operator=( other ); superentitiesCounts = other.superentitiesCounts; @@ -137,7 +132,7 @@ protected: void print( std::ostream& str ) const { BaseType::print( str ); - str << "Adjacency matrix for superentities with dimension " << SuperdimensionTag::value << " of entities with dimension " << EntityTopology::dimension << " is: " << std::endl; + str << "Adjacency matrix for superentities with dimension " << SuperdimensionTag::value << " of entities with dimension " << EntityDimensionTag::value << " is: " << std::endl; str << matrix << std::endl; } @@ -186,12 +181,12 @@ private: template< typename MeshConfig, typename Device, - typename EntityTopology, + typename EntityDimensionTag, typename SuperdimensionTag > -class SuperentityStorageLayer< MeshConfig, Device, EntityTopology, SuperdimensionTag, false > - : public SuperentityStorageLayer< MeshConfig, Device, EntityTopology, typename SuperdimensionTag::Decrement > +class SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, SuperdimensionTag, false > + : public SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, typename SuperdimensionTag::Decrement > { - using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityTopology, typename SuperdimensionTag::Decrement >; + using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, typename SuperdimensionTag::Decrement >; public: // inherit constructors and assignment operators (including templated versions) using BaseType::BaseType; @@ -201,18 +196,21 @@ public: // termination of recursive inheritance (everything is reduced to EntityStorage == false thanks to the WeakSuperentityStorageTrait) template< typename MeshConfig, typename Device, - typename EntityTopology > -class SuperentityStorageLayer< MeshConfig, Device, EntityTopology, DimensionTag< EntityTopology::dimension >, false > + typename EntityDimensionTag > +class SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, EntityDimensionTag, false > { - using SuperdimensionTag = DimensionTag< EntityTopology::dimension >; + using SuperdimensionTag = EntityDimensionTag; protected: SuperentityStorageLayer() = default; - explicit SuperentityStorageLayer( const SuperentityStorageLayer& other ) {} + explicit SuperentityStorageLayer( const SuperentityStorageLayer& other ) = default; + SuperentityStorageLayer( SuperentityStorageLayer&& other ) = default; template< typename Device_ > - SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopology, SuperdimensionTag >& other ) {} + SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityDimensionTag, SuperdimensionTag >& other ) {} + SuperentityStorageLayer& operator=( const SuperentityStorageLayer& other ) = default; + SuperentityStorageLayer& operator=( SuperentityStorageLayer&& other ) = default; template< typename Device_ > - SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopology, SuperdimensionTag >& other ) { return *this; } + SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityDimensionTag, SuperdimensionTag >& other ) { return *this; } void getSuperentitiesCountsArray() {} diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h index 2bf7f856fc6cc8c7ad0a2963b308f8b4c9fb2421..cc7fbe4f2e42a70083402e3ae4dad5233c96833c 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h @@ -29,25 +29,44 @@ namespace Meshes { template< typename MeshConfig, typename Device, typename EntityTopology > class MeshEntity; +/**** + * Mesh entity traits with specializations + * + * DYNAMIC TOPOLOGY + * FALSE + */ template< typename MeshConfig, - typename DimensionTag > -struct EntityTopologyGetter + typename Device, + int Dimension > +class MeshEntityTraits< MeshConfig, Device, Dimension, false > { - static_assert( DimensionTag::value <= MeshConfig::meshDimension, "There are no entities with dimension higher than the mesh dimension." ); - using Topology = typename Topologies::Subtopology< typename MeshConfig::CellTopology, DimensionTag::value >::Topology; -}; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; -template< typename MeshConfig > -struct EntityTopologyGetter< MeshConfig, DimensionTag< MeshConfig::CellTopology::dimension > > -{ - using Topology = typename MeshConfig::CellTopology; -}; +public: + static_assert( 0 <= Dimension && Dimension <= MeshConfig::meshDimension, "invalid dimension" ); + using EntityTopology = typename EntityTopologyGetter< MeshConfig, DimensionTag< Dimension > >::Topology; + using EntityType = MeshEntity< MeshConfig, Device, EntityTopology >; + using SeedType = EntitySeed< MeshConfig, EntityTopology >; + + using SeedIndexedSetType = Containers::UnorderedIndexedSet< SeedType, GlobalIndexType, typename SeedType::HashType, typename SeedType::KeyEqual >; + using SeedSetType = std::unordered_set< typename SeedIndexedSetType::key_type, typename SeedIndexedSetType::hasher, typename SeedIndexedSetType::key_equal >; + using SeedMatrixType = EntitySeedMatrix< MeshConfig, EntityTopology >; + // container for storing the subentity indices + using SubentityMatrixType = Matrices::SparseMatrix< bool, Device, GlobalIndexType, Matrices::GeneralMatrix, EllpackSegments >; +}; + +/**** + * Mesh entity traits with specializations + * + * DYNAMIC TOPOLOGY + * TRUE + */ template< typename MeshConfig, typename Device, int Dimension > -class MeshEntityTraits +class MeshEntityTraits< MeshConfig, Device, Dimension, true > { using GlobalIndexType = typename MeshConfig::GlobalIndexType; @@ -57,9 +76,13 @@ public: using EntityTopology = typename EntityTopologyGetter< MeshConfig, DimensionTag< Dimension > >::Topology; using EntityType = MeshEntity< MeshConfig, Device, EntityTopology >; using SeedType = EntitySeed< MeshConfig, EntityTopology >; - + using SeedIndexedSetType = Containers::UnorderedIndexedSet< SeedType, GlobalIndexType, typename SeedType::HashType, typename SeedType::KeyEqual >; using SeedSetType = std::unordered_set< typename SeedIndexedSetType::key_type, typename SeedIndexedSetType::hasher, typename SeedIndexedSetType::key_equal >; + using SeedMatrixType = EntitySeedMatrix< MeshConfig, EntityTopology >; + + // container for storing the subentity indices + using SubentityMatrixType = Matrices::SparseMatrix< bool, Device, GlobalIndexType, Matrices::GeneralMatrix, SlicedEllpackSegments >; }; } // namespace Meshes diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h index 830db3f2bb4d8d39ea7a6ee7ad7cdd5bf9eca626..0f191784e6e4b3c731ca43cb416a5415ac24aa30 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h @@ -23,11 +23,17 @@ namespace TNL { namespace Meshes { +/**** + * Mesh subentity traits with specializations + * + * DYNAMIC TOPOLOGY + * FALSE + */ template< typename MeshConfig, typename Device, typename EntityTopology, int Dimension > -class MeshSubentityTraits +class MeshSubentityTraits< MeshConfig, Device, EntityTopology, Dimension, false > { using GlobalIndexType = typename MeshConfig::GlobalIndexType; using LocalIndexType = typename MeshConfig::LocalIndexType; @@ -54,5 +60,30 @@ public: }; }; +/**** + * Mesh subentity traits with specializations + * + * DYNAMIC TOPOLOGY + * TRUE + */ +template< typename MeshConfig, + typename Device, + typename EntityTopology, + int Dimension > +class MeshSubentityTraits< MeshConfig, Device, EntityTopology, Dimension, true > +{ + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + +public: + static_assert( 0 <= Dimension && Dimension <= MeshConfig::meshDimension, "invalid dimension" ); + static_assert( EntityTopology::dimension > Dimension, "Subentity dimension must be smaller than the entity dimension." ); + + static constexpr bool storageEnabled = MeshConfig::subentityStorage( EntityTopology::dimension, Dimension ); + + using SubentityTopology = typename MeshEntityTraits< MeshConfig, Device, Dimension >::EntityTopology; + using SubentityType = typename MeshEntityTraits< MeshConfig, Device, Dimension >::EntityType; +}; + } // namespace Meshes } // namespace TNL diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h index 3f8c5f4441e958ed2f9c623a98a490cf1368f3e9..21e28b63f0b2d23837a0c63b3d833f2f04977fba 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h @@ -19,18 +19,51 @@ #include #include #include +#include #include #include #include #include +#include +#include namespace TNL { namespace Meshes { template< typename MeshConfig, typename Device, typename EntityTopology > class MeshEntity; -template< typename MeshConfig, typename EntityTopology > class EntitySeed; -template< typename MeshConfig, typename Device, int Dimension > class MeshEntityTraits; -template< typename MeshConfig, typename Device, typename MeshEntity, int Subdimension > class MeshSubentityTraits; + +template< typename MeshConfig, + typename EntityTopology, + bool IsDynamicTopology = Topologies::IsDynamicTopology< EntityTopology >::value > +class EntitySeed; + +template< typename MeshConfig, + typename DimensionTag > +struct EntityTopologyGetter +{ + static_assert( DimensionTag::value <= MeshConfig::meshDimension, "There are no entities with dimension higher than the mesh dimension." ); + using Topology = typename Topologies::Subtopology< typename MeshConfig::CellTopology, DimensionTag::value >::Topology; +}; + +template< typename MeshConfig > +struct EntityTopologyGetter< MeshConfig, DimensionTag< MeshConfig::CellTopology::dimension > > +{ + using Topology = typename MeshConfig::CellTopology; +}; + +template< typename MeshConfig, + typename Device, + int Dimension, + bool IsDynamicTopology = Topologies::IsDynamicTopology< typename EntityTopologyGetter< MeshConfig, DimensionTag< Dimension > >::Topology >::value > +class MeshEntityTraits; + +template< typename MeshConfig, + typename Device, + typename EntityTopology, + int Dimension, + bool IsDynamicTopology = Topologies::IsDynamicTopology< EntityTopology >::value > +class MeshSubentityTraits; + template< typename MeshConfig, typename Device, typename MeshEntity, int Superdimension > class MeshSuperentityTraits; // helper templates (must be public because nvcc sucks, and outside of MeshTraits to avoid duplicate code generation) @@ -52,15 +85,19 @@ public: using LocalIndexType = typename MeshConfig::LocalIndexType; using CellTopology = typename MeshConfig::CellTopology; + using FaceTopology = typename Topologies::Subtopology< CellTopology, meshDimension - 1 >::Topology; using CellType = MeshEntity< MeshConfig, Device, CellTopology >; using VertexType = MeshEntity< MeshConfig, Device, Topologies::Vertex >; using PointType = Containers::StaticVector< spaceDimension, typename MeshConfig::RealType >; + using FaceSeedType = EntitySeed< MeshConfig, FaceTopology >; using CellSeedType = EntitySeed< MeshConfig, CellTopology >; using EntityTagType = std::uint8_t; using NeighborCountsArray = Containers::Vector< LocalIndexType, DeviceType, GlobalIndexType >; using PointArrayType = Containers::Array< PointType, DeviceType, GlobalIndexType >; - using CellSeedArrayType = Containers::Array< CellSeedType, DeviceType, GlobalIndexType >; + using FaceSeedMatrixType = EntitySeedMatrix< MeshConfig, FaceTopology >; + using CellSeedMatrixType = EntitySeedMatrix< MeshConfig, CellTopology >; + using EntityTagsArrayType = Containers::Array< EntityTagType, DeviceType, GlobalIndexType >; template< int Dimension > @@ -75,7 +112,8 @@ public: using DimensionTag = Meshes::DimensionTag< meshDimension >; // container for storing the subentity indices - using SubentityMatrixType = Matrices::SparseMatrix< bool, Device, GlobalIndexType, Matrices::GeneralMatrix, EllpackSegments >; + template< int Dimension > + using SubentityMatrixType = typename EntityTraits< Dimension >::SubentityMatrixType; // container for storing the superentity indices using SuperentityMatrixType = Matrices::SparseMatrix< bool, Device, GlobalIndexType, Matrices::GeneralMatrix, SlicedEllpackSegments >; diff --git a/src/TNL/Meshes/Readers/FPMAReader.h b/src/TNL/Meshes/Readers/FPMAReader.h new file mode 100644 index 0000000000000000000000000000000000000000..11919c89f082c8fc204b04b642f42776f2e5d6b7 --- /dev/null +++ b/src/TNL/Meshes/Readers/FPMAReader.h @@ -0,0 +1,171 @@ +#pragma once + +#include +#include +#include + +#include + +namespace TNL { +namespace Meshes { +namespace Readers { + +class FPMAReader +: public MeshReader +{ +public: + FPMAReader() = default; + + FPMAReader( const std::string& fileName ) + : MeshReader( fileName ) + {} + + virtual void detectMesh() override + { + reset(); + + std::ifstream inputFile( fileName ); + if( ! inputFile ) + throw MeshReaderError( "FPMAReader", "failed to open the file '" + fileName + "'." ); + + std::string line; + std::istringstream iss; + + // fpma format doesn't provide types + using PointType = double; + pointsType = "double"; + connectivityType = offsetsType = "std::int32_t"; + + // it is expected, that fpma format always stores polyhedral mesh + spaceDimension = meshDimension = 3; + cellShape = VTK::EntityShape::Polyhedron; + + // arrays holding the data from the file + std::vector< double > pointsArray; + std::vector< std::int32_t > cellConnectivityArray, cellOffsetsArray; + std::vector< std::int32_t > faceConnectivityArray, faceOffsetsArray; + + // read number of points + NumberOfPoints = readValue< decltype(NumberOfPoints) >( inputFile ); + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read number of points, the file may be invalid or corrupted." ); + } + pointsArray.reserve( NumberOfPoints ); + // read points + for( std::size_t pointIndex = 0; pointIndex < NumberOfPoints; pointIndex++ ) { + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read enough vertices, the file may be invalid or corrupted." ); + } + + // read the coordinates of a point + for( int i = 0; i < 3; i++ ) { + PointType aux = readValue< PointType >( inputFile ); + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read " + std::to_string(i) + "th component of the vertex number " + std::to_string(pointIndex) + "." ); + } + pointsArray.emplace_back( aux ); + } + } + + // read number of faces + NumberOfFaces = readValue< decltype(NumberOfFaces) >( inputFile ); + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read number of faces, the file may be invalid or corrupted." ); + } + + // read faces + faceConnectivityArray.reserve( NumberOfFaces ); + faceOffsetsArray.reserve( NumberOfFaces ); + for( std::size_t faceIndex = 0; faceIndex < NumberOfFaces; faceIndex++ ) { + + // read number of points of a face + size_t numberOfFacePoints = readValue< decltype(numberOfFacePoints) >( inputFile ); + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read enough faces, the file may be invalid or corrupted." ); + } + + // read points of a face + for( std::size_t i = 0; i < numberOfFacePoints; i++ ) { + size_t pointIndex = readValue< decltype(pointIndex) >( inputFile ); + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read " + std::to_string(i) + "th component of the face number " + std::to_string(faceIndex) + "." ); + } + faceConnectivityArray.emplace_back( pointIndex ); + } + + faceOffsetsArray.emplace_back( faceConnectivityArray.size() ); + } + + // read number of cells + NumberOfCells = readValue< decltype(NumberOfCells) >( inputFile ); + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read number of cells, the file may be invalid or corrupted." ); + } + + // read cells + cellConnectivityArray.reserve( NumberOfCells ); + cellOffsetsArray.reserve( NumberOfCells ); + for( std::size_t cellIndex = 0; cellIndex < NumberOfCells; cellIndex++ ) { + + // read number of faces of a cell + size_t numberOfCellFaces = readValue< decltype(numberOfCellFaces) >( inputFile ); + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read enough cells, the file may be invalid or corrupted." ); + } + + // read faces of a cell + for( std::size_t i = 0; i < numberOfCellFaces; i++ ) { + std::uint32_t faceIndex = readValue< decltype(faceIndex) >( inputFile ); + if( ! iss ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read " + std::to_string(i) + "th component of the cell number " + std::to_string(cellIndex) + "." ); + } + cellConnectivityArray.emplace_back( faceIndex ); + } + + cellOffsetsArray.emplace_back( cellConnectivityArray.size() ); + } + + // set the arrays to the base class + this->pointsArray = std::move(pointsArray); + this->cellConnectivityArray = std::move(cellConnectivityArray); + this->cellOffsetsArray = std::move(cellOffsetsArray); + this->faceConnectivityArray = std::move(faceConnectivityArray); + this->faceOffsetsArray = std::move(faceOffsetsArray); + + // indicate success by setting the mesh type + meshType = "Meshes::Mesh"; + } +private: + template< typename T > + T readValue( std::ifstream& ifs ) + { + skipComments( ifs ); + T val; + ifs >> val; + return val; + } + + void skipComments( std::ifstream& ifs ) + { + ifs >> std::ws; + int c = ifs.peek(); + while( c == '#' && c != EOF ) { + ifs.ignore( std::numeric_limits::max(), '\n' ); // skip to the next line + ifs >> std::ws; + c = ifs.peek(); + } + } +}; + +} // namespace Readers +} // namespace Meshes +} // namespace TNL diff --git a/src/TNL/Meshes/Readers/MeshReader.h b/src/TNL/Meshes/Readers/MeshReader.h index 6d7398c28791a027f35b92eb908d08dd86ac8848..e18e6577bf949f52f3b80c442c8dd913d5966e8c 100644 --- a/src/TNL/Meshes/Readers/MeshReader.h +++ b/src/TNL/Meshes/Readers/MeshReader.h @@ -167,13 +167,14 @@ public: + "of cells used in the file (" + VTK::getShapeName(cellShape) + ")" ); using MeshBuilder = MeshBuilder< MeshType >; + using NeighborCountsArray = typename MeshBuilder::NeighborCountsArray; using PointType = typename MeshType::PointType; + using FaceSeedType = typename MeshBuilder::FaceSeedType; using CellSeedType = typename MeshBuilder::CellSeedType; MeshBuilder meshBuilder; - meshBuilder.setPointsCount( NumberOfPoints ); - meshBuilder.setCellsCount( NumberOfCells ); - + meshBuilder.setEntitiesCount( NumberOfPoints, NumberOfCells, NumberOfFaces ); + // assign points visit( [&meshBuilder](auto&& array) { PointType p; @@ -190,25 +191,66 @@ public: pointsArray ); + // assign faces + visit( [this, &meshBuilder](auto&& connectivity) { + // let's just assume that the connectivity and offsets arrays have the same type... + using mpark::get; + const auto& offsets = get< std::decay_t >( faceOffsetsArray ); + + // Set corners counts + NeighborCountsArray cornersCounts( NumberOfFaces ); + std::size_t offsetStart = 0; + for( std::size_t i = 0; i < NumberOfFaces; i++ ) { + const std::size_t offsetEnd = offsets[ i ]; + cornersCounts[ i ] = offsetEnd - offsetStart; + offsetStart = offsetEnd; + } + meshBuilder.setFaceCornersCounts( std::move( cornersCounts ) ); + + // Set corner ids + offsetStart = 0; + for( std::size_t i = 0; i < NumberOfFaces; i++ ) { + FaceSeedType seed = meshBuilder.getFaceSeed( i ); + const std::size_t offsetEnd = offsets[ i ]; + for( std::size_t o = offsetStart; o < offsetEnd; o++ ) + seed.setCornerId( o - offsetStart, connectivity[ o ] ); + offsetStart = offsetEnd; + } + }, + faceConnectivityArray + ); + // assign cells visit( [this, &meshBuilder](auto&& connectivity) { // let's just assume that the connectivity and offsets arrays have the same type... using mpark::get; - const auto& offsets = get< std::decay_t >( offsetsArray ); + const auto& offsets = get< std::decay_t >( cellOffsetsArray ); + + // Set corners counts + NeighborCountsArray cornersCounts( NumberOfCells ); std::size_t offsetStart = 0; for( std::size_t i = 0; i < NumberOfCells; i++ ) { - CellSeedType& seed = meshBuilder.getCellSeed( i ); + const std::size_t offsetEnd = offsets[ i ]; + cornersCounts[ i ] = offsetEnd - offsetStart; + offsetStart = offsetEnd; + } + meshBuilder.setCellCornersCounts( std::move( cornersCounts ) ); + + // Set corner ids + offsetStart = 0; + for( std::size_t i = 0; i < NumberOfCells; i++ ) { + CellSeedType seed = meshBuilder.getCellSeed( i ); const std::size_t offsetEnd = offsets[ i ]; for( std::size_t o = offsetStart; o < offsetEnd; o++ ) seed.setCornerId( o - offsetStart, connectivity[ o ] ); offsetStart = offsetEnd; } }, - connectivityArray + cellConnectivityArray ); // reset arrays since they are not needed anymore - pointsArray = connectivityArray = offsetsArray = typesArray = {}; + pointsArray = faceConnectivityArray = cellConnectivityArray = faceOffsetsArray = cellOffsetsArray = typesArray = {}; if( ! meshBuilder.build( mesh ) ) throw MeshReaderError( "MeshReader", "MeshBuilder failed" ); @@ -223,7 +265,7 @@ public: virtual VariantVector readCellData( std::string arrayName ) { - throw Exceptions::NotImplementedError( "readPointData is not implemented in the mesh reader for this specific file format." ); + throw Exceptions::NotImplementedError( "readCellData is not implemented in the mesh reader for this specific file format." ); } std::string @@ -278,7 +320,7 @@ protected: std::string meshType; // attributes of the mesh - std::size_t NumberOfPoints, NumberOfCells; + std::size_t NumberOfPoints, NumberOfFaces, NumberOfCells; int meshDimension, spaceDimension; VTK::EntityShape cellShape = VTK::EntityShape::Vertex; @@ -288,21 +330,26 @@ protected: // intermediate representation of the unstructured mesh (matches the VTU // file format, other formats have to be converted) - VariantVector pointsArray, connectivityArray, offsetsArray, typesArray; + VariantVector pointsArray, cellConnectivityArray, cellOffsetsArray, + faceConnectivityArray, faceOffsetsArray, + typesArray; + + + // string representation of each array's value type std::string pointsType, connectivityType, offsetsType, typesType; void resetBase() { meshType = ""; - NumberOfPoints = NumberOfCells = 0; + NumberOfPoints = NumberOfFaces = NumberOfCells = 0; meshDimension = spaceDimension = 0; cellShape = VTK::EntityShape::Vertex; gridExtent = {}; gridOrigin = gridSpacing = {}; - pointsArray = connectivityArray = offsetsArray = typesArray = {}; + pointsArray = cellConnectivityArray = cellOffsetsArray = faceConnectivityArray = faceOffsetsArray = typesArray = {}; pointsType = connectivityType = offsetsType = typesType = ""; } }; diff --git a/src/TNL/Meshes/Readers/NetgenReader.h b/src/TNL/Meshes/Readers/NetgenReader.h index 432776ec48b011efd1aa94f5a5977faeaa228f74..51a1737b839c1a98ae613b8a8d9ffb20f131a462 100644 --- a/src/TNL/Meshes/Readers/NetgenReader.h +++ b/src/TNL/Meshes/Readers/NetgenReader.h @@ -149,8 +149,8 @@ public: // set the arrays to the base class this->pointsArray = std::move(pointsArray); - this->connectivityArray = std::move(connectivityArray); - this->offsetsArray = std::move(offsetsArray); + this->cellConnectivityArray = std::move(connectivityArray); + this->cellOffsetsArray = std::move(offsetsArray); this->typesArray = std::move(typesArray); // indicate success by setting the mesh type diff --git a/src/TNL/Meshes/Readers/VTKReader.h b/src/TNL/Meshes/Readers/VTKReader.h index a4a1c943ea92cdcd7ddf484ccef0c1bf1fd16fc4..966e4f4677c1dcbbe742c786f5038615aca88676 100644 --- a/src/TNL/Meshes/Readers/VTKReader.h +++ b/src/TNL/Meshes/Readers/VTKReader.h @@ -19,6 +19,7 @@ #include #include +#include namespace TNL { namespace Meshes { @@ -157,13 +158,35 @@ public: } // validate cell types + using PolygonShapeGroupChecker = VTK::EntityShapeGroupChecker< VTK::EntityShape::Polygon >; + //TODO: add EntityShapeGroup for polyhedrons and uncomment line below + //using PolyhedralShapeGroupChecker = VTK::EntityShapeGroupChecker< VTK::EntityShape::Polyhedral >; cellShape = (VTK::EntityShape) cellTypes[0]; + for( auto c : cellTypes ) - if( (VTK::EntityShape) c != cellShape ) { - const std::string msg = "Mixed unstructured meshes are not supported. There are cells with type " - + VTK::getShapeName(cellShape) + " and " + VTK::getShapeName((VTK::EntityShape) c); - throw MeshReaderError( "VTKReader", msg ); + { + auto entityShape = (VTK::EntityShape) c; + if( cellShape != entityShape ) + { + //in case input mesh includes mixed shapes, use more general cellShape ( polygon for 2D, polyhedrals for 3D ) + if( PolygonShapeGroupChecker::bothBelong( cellShape, entityShape ) ) + { + cellShape = PolygonShapeGroupChecker::GeneralShape; + } + //TODO: add group check for polyhedrals later + /*else if( PolyhedralEntityShapeGroupChecker::bothBelong( cellShape, entityShape ) ) + { + cellShape = PolyhedralEntityShapeGroupChecker::GeneralShape; + }*/ + else + { + const std::string msg = "Mixed unstructured meshes are not supported. There are cells with type " + + VTK::getShapeName(cellShape) + " and " + VTK::getShapeName(entityShape) + "."; + reset(); + throw MeshReaderError( "VTKReader", msg ); + } } + } // find to the CELLS section if( ! sectionPositions.count( "CELLS" ) ) @@ -177,7 +200,15 @@ public: throw MeshReaderError( "VTKReader", "unable to read enough cells, the file may be invalid or corrupted" " (entityIndex = " + std::to_string(entityIndex) + ")" ); - if( (VTK::EntityShape) typesArray[ entityIndex ] == cellShape ) { + VTK::EntityShape entityShape = (VTK::EntityShape) typesArray[ entityIndex ]; + + // TODO: Polyhedrons will require to create polygon subentity seeds from given entityShapes + // and add their entries to faceConnectivityArray and faceOffsetsArray. + // CellConnectivityArray and cellOffsetsArray will contain indices addressing created polygon subentities. + if( entityShape == cellShape || + PolygonShapeGroupChecker::bothBelong( cellShape, entityShape ) ) { + iss.clear(); + iss.str( line ); // read number of subvertices const std::int32_t subvertices = readValue< std::int32_t >( dataFormat, inputFile ); for( int v = 0; v < subvertices; v++ ) { @@ -203,8 +234,8 @@ public: // set the arrays to the base class this->pointsArray = std::move(pointsArray); - this->connectivityArray = std::move(connectivityArray); - this->offsetsArray = std::move(offsetsArray); + this->cellConnectivityArray = std::move(connectivityArray); + this->cellOffsetsArray = std::move(offsetsArray); this->typesArray = std::move(typesArray); // indicate success by setting the mesh type diff --git a/src/TNL/Meshes/Readers/VTUReader.h b/src/TNL/Meshes/Readers/VTUReader.h index bae1c3381caa6ce3a3f09b592b7001d707b5d3a4..08450b0fee1701932937bc63cb2629c763a91997 100644 --- a/src/TNL/Meshes/Readers/VTUReader.h +++ b/src/TNL/Meshes/Readers/VTUReader.h @@ -13,6 +13,7 @@ #pragma once #include +#include namespace TNL { namespace Meshes { @@ -49,9 +50,9 @@ class VTUReader // read the points, connectivity, offsets and types into intermediate arrays pointsArray = readDataArray( pointsData, "Points" ); pointsType = VTKDataTypes.at( getAttributeString( pointsData, "type" ) ); - connectivityArray = readDataArray( connectivity, "connectivity" ); + cellConnectivityArray = readDataArray( connectivity, "connectivity" ); connectivityType = VTKDataTypes.at( getAttributeString( connectivity, "type" ) ); - offsetsArray = readDataArray( offsets, "offsets" ); + cellOffsetsArray = readDataArray( offsets, "offsets" ); offsetsType = VTKDataTypes.at( getAttributeString( offsets, "type" ) ); typesArray = readDataArray( types, "types" ); typesType = VTKDataTypes.at( getAttributeString( types, "type" ) ); @@ -94,11 +95,32 @@ class VTUReader return; cellShape = (VTK::EntityShape) array[0]; meshDimension = getEntityDimension( cellShape ); + using PolygonShapeGroupChecker = VTK::EntityShapeGroupChecker< VTK::EntityShape::Polygon >; + //TODO: uncomment line below later for polyhedrals + //using PolyhedralShapeGroupChecker = VTK::EntityShapeGroupChecker< VTK::EntityShape::Polyhedral >; + // TODO: check only entities of the same dimension (edges, faces and cells separately) for( auto c : array ) - if( (VTK::EntityShape) c != cellShape ) - throw MeshReaderError( "VTUReader", "Mixed unstructured meshes are not supported. There are cells with type " - + VTK::getShapeName(cellShape) + " and " + VTK::getShapeName((VTK::EntityShape) c) + "." ); + { + VTK::EntityShape entityShape = (VTK::EntityShape) c; + if( entityShape != cellShape ) + { + if( PolygonShapeGroupChecker::bothBelong( cellShape, entityShape ) ) + { + cellShape = PolygonShapeGroupChecker::GeneralShape; + } + //TODO: add group check for polyhedrals later + /*else if( PolyhedralEntityShapeGroupChecker::bothBelong( cellShape, entityShape ) ) + { + cellShape = PolyhedralEntityShapeGroupChecker::GeneralShape; + }*/ + else + { + throw MeshReaderError( "VTUReader", "Mixed unstructured meshes are not supported. There are cells with type " + + VTK::getShapeName(cellShape) + " and " + VTK::getShapeName(entityShape) + "." ); + } + } + } }, typesArray ); @@ -113,7 +135,7 @@ class VTUReader max_offset = c; } }, - offsetsArray + cellOffsetsArray ); // validate connectivity visit( [this, max_offset](auto&& array) { @@ -124,7 +146,7 @@ class VTUReader throw MeshReaderError( "VTUReader", "connectivity index " + std::to_string(c) + " is out of range" ); } }, - connectivityArray + cellConnectivityArray ); } #endif diff --git a/src/TNL/Meshes/Readers/getMeshReader.h b/src/TNL/Meshes/Readers/getMeshReader.h index 41976dcfd3a65584665423d83a60f37e45ff9221..4003ec6f1245fc88693c0d5d15e6719aa171bb20 100644 --- a/src/TNL/Meshes/Readers/getMeshReader.h +++ b/src/TNL/Meshes/Readers/getMeshReader.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace TNL { namespace Meshes { @@ -51,6 +52,8 @@ getMeshReader( const std::string& fileName, return std::make_shared< Readers::PVTUReader >( fileName ); else if( format == "pvti" ) return std::make_shared< Readers::PVTIReader >( fileName ); + else if( format == "fpma" ) + return std::make_shared< Readers::FPMAReader >( fileName ); if( fileFormat == "auto" ) std::cerr << "File '" << fileName << "' has unsupported format (based on the file extension): " << format << "."; diff --git a/src/TNL/Meshes/Topologies/IsDynamicTopology.h b/src/TNL/Meshes/Topologies/IsDynamicTopology.h new file mode 100644 index 0000000000000000000000000000000000000000..0cb52358a589c963c70f931ae57f69d06db6f8dc --- /dev/null +++ b/src/TNL/Meshes/Topologies/IsDynamicTopology.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +namespace TNL { +namespace Meshes { +namespace Topologies { + +/** + * \brief Type trait for checking if Topology has at least one missing Subtopology< Topology, D > >::count for all D from Topology::dimension - 1 to 0 + */ +template< typename Topology, int D = Topology::dimension > +struct IsDynamicTopology +{ + enum : bool { value = !HasCountMember< Subtopology< Topology, D - 1 > >::value || + IsDynamicTopology< Topology, D - 1 >::value }; +}; + +/** + * \brief Specialization for Vertex Topology + */ +template<> +struct IsDynamicTopology< Vertex, 0 > : std::false_type +{}; + +/** + * \brief Specialization for D = 1 to end recursion + */ +template< typename Topology > +struct IsDynamicTopology< Topology, 1 > +{ + enum : bool { value = !HasCountMember< Subtopology< Topology, 0 > >::value }; +}; + +} // namespace Topologies +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Topologies/Polygon.h b/src/TNL/Meshes/Topologies/Polygon.h new file mode 100644 index 0000000000000000000000000000000000000000..558f5a0ec998e7cc81a5b62cc3d2b1df1ed97684 --- /dev/null +++ b/src/TNL/Meshes/Topologies/Polygon.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace TNL { +namespace Meshes { +namespace Topologies { + +struct Polygon +{ + static constexpr int dimension = 2; +}; + +template<> +struct Subtopology< Polygon, 0 > +{ + typedef Vertex Topology; +}; + +template<> +struct Subtopology< Polygon, 1 > +{ + typedef Edge Topology; +}; + +} // namespace Topologies +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Topologies/Polyhedron.h b/src/TNL/Meshes/Topologies/Polyhedron.h new file mode 100644 index 0000000000000000000000000000000000000000..03f5b7a090dcc7b4b9d93835f35749764577e835 --- /dev/null +++ b/src/TNL/Meshes/Topologies/Polyhedron.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace TNL { +namespace Meshes { +namespace Topologies { + +struct Polyhedron +{ + static constexpr int dimension = 3; +}; + +template<> +struct Subtopology< Polyhedron, 0 > +{ + typedef Vertex Topology; +}; + +template<> +struct Subtopology< Polyhedron, 1 > +{ + typedef Edge Topology; +}; + +template<> +struct Subtopology< Polyhedron, 2 > +{ + typedef Polygon Topology; +}; + +} // namespace Topologies +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Topologies/Pyramid.h b/src/TNL/Meshes/Topologies/Pyramid.h new file mode 100644 index 0000000000000000000000000000000000000000..83edec19494f6d66d7be7cddb54faaa61ad05b42 --- /dev/null +++ b/src/TNL/Meshes/Topologies/Pyramid.h @@ -0,0 +1,118 @@ +#pragma once + +#include +#include + +namespace TNL { +namespace Meshes { +namespace Topologies { + +struct Pyramid +{ + static constexpr int dimension = 3; +}; + + +template<> +struct Subtopology< Pyramid, 0 > +{ + typedef Vertex Topology; + + static constexpr int count = 5; +}; + +template<> +struct Subtopology< Pyramid, 1 > +{ + typedef Edge Topology; + + static constexpr int count = 8; +}; + +template<> +struct Subtopology< Pyramid, 2 > +{ + typedef Polygon Topology; + + static constexpr int count = 5; +}; + + +template<> struct SubentityVertexMap< Pyramid, Edge, 0, 0> { enum { index = 0 }; }; +template<> struct SubentityVertexMap< Pyramid, Edge, 0, 1> { enum { index = 1 }; }; + +template<> struct SubentityVertexMap< Pyramid, Edge, 1, 0> { enum { index = 1 }; }; +template<> struct SubentityVertexMap< Pyramid, Edge, 1, 1> { enum { index = 2 }; }; + +template<> struct SubentityVertexMap< Pyramid, Edge, 2, 0> { enum { index = 2 }; }; +template<> struct SubentityVertexMap< Pyramid, Edge, 2, 1> { enum { index = 3 }; }; + +template<> struct SubentityVertexMap< Pyramid, Edge, 3, 0> { enum { index = 3 }; }; +template<> struct SubentityVertexMap< Pyramid, Edge, 3, 1> { enum { index = 0 }; }; + +template<> struct SubentityVertexMap< Pyramid, Edge, 4, 0> { enum { index = 0 }; }; +template<> struct SubentityVertexMap< Pyramid, Edge, 4, 1> { enum { index = 4 }; }; + +template<> struct SubentityVertexMap< Pyramid, Edge, 5, 0> { enum { index = 1 }; }; +template<> struct SubentityVertexMap< Pyramid, Edge, 5, 1> { enum { index = 4 }; }; + +template<> struct SubentityVertexMap< Pyramid, Edge, 6, 0> { enum { index = 2 }; }; +template<> struct SubentityVertexMap< Pyramid, Edge, 6, 1> { enum { index = 4 }; }; + +template<> struct SubentityVertexMap< Pyramid, Edge, 7, 0> { enum { index = 3 }; }; +template<> struct SubentityVertexMap< Pyramid, Edge, 7, 1> { enum { index = 4 }; }; + +template <> +struct SubentityVertexCount< Pyramid, Polygon, 0 > +{ + static constexpr int count = 4; +}; + +template<> struct SubentityVertexMap< Pyramid, Polygon, 0, 0> { enum { index = 0 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 0, 1> { enum { index = 1 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 0, 2> { enum { index = 2 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 0, 3> { enum { index = 3 }; }; + +template <> +struct SubentityVertexCount< Pyramid, Polygon, 1 > +{ + static constexpr int count = 3; +}; + +template<> struct SubentityVertexMap< Pyramid, Polygon, 1, 0> { enum { index = 0 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 1, 1> { enum { index = 1 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 1, 2> { enum { index = 4 }; }; + +template <> +struct SubentityVertexCount< Pyramid, Polygon, 2 > +{ + static constexpr int count = 3; +}; + +template<> struct SubentityVertexMap< Pyramid, Polygon, 2, 0> { enum { index = 1 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 2, 1> { enum { index = 2 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 2, 2> { enum { index = 4 }; }; + +template <> +struct SubentityVertexCount< Pyramid, Polygon, 3 > +{ + static constexpr int count = 3; +}; + +template<> struct SubentityVertexMap< Pyramid, Polygon, 3, 0> { enum { index = 2 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 3, 1> { enum { index = 3 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 3, 2> { enum { index = 4 }; }; + +template <> +struct SubentityVertexCount< Pyramid, Polygon, 4 > +{ + static constexpr int count = 3; +}; + +template<> struct SubentityVertexMap< Pyramid, Polygon, 4, 0> { enum { index = 3 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 4, 1> { enum { index = 0 }; }; +template<> struct SubentityVertexMap< Pyramid, Polygon, 4, 2> { enum { index = 4 }; }; + +} // namespace Topologies +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Topologies/SubentityVertexCount.h b/src/TNL/Meshes/Topologies/SubentityVertexCount.h new file mode 100644 index 0000000000000000000000000000000000000000..275be9d96b371c31bcc02dfeb1597a4cc1bb031a --- /dev/null +++ b/src/TNL/Meshes/Topologies/SubentityVertexCount.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace TNL { +namespace Meshes{ +namespace Topologies { + +template< typename EntityTopology, + typename SubentityTopology, + int SubentityIndex > +struct SubentityVertexCount +{ + static constexpr int count = Subtopology< SubentityTopology, 0 >::count; +}; + +} // namespace Topologies +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Topologies/Wedge.h b/src/TNL/Meshes/Topologies/Wedge.h new file mode 100644 index 0000000000000000000000000000000000000000..2cd3321944dd59fcf20a3230adb5ab1c9c7e3899 --- /dev/null +++ b/src/TNL/Meshes/Topologies/Wedge.h @@ -0,0 +1,123 @@ +#pragma once + +#include +#include + +namespace TNL { +namespace Meshes { +namespace Topologies { + +struct Wedge +{ + static constexpr int dimension = 3; +}; + + +template<> +struct Subtopology< Wedge, 0 > +{ + typedef Vertex Topology; + + static constexpr int count = 6; +}; + +template<> +struct Subtopology< Wedge, 1 > +{ + typedef Edge Topology; + + static constexpr int count = 9; +}; + +template<> +struct Subtopology< Wedge, 2 > +{ + typedef Polygon Topology; + + static constexpr int count = 5; +}; + +template<> struct SubentityVertexMap< Wedge, Edge, 0, 0> { enum { index = 0 }; }; +template<> struct SubentityVertexMap< Wedge, Edge, 0, 1> { enum { index = 1 }; }; + +template<> struct SubentityVertexMap< Wedge, Edge, 1, 0> { enum { index = 1 }; }; +template<> struct SubentityVertexMap< Wedge, Edge, 1, 1> { enum { index = 2 }; }; + +template<> struct SubentityVertexMap< Wedge, Edge, 2, 0> { enum { index = 2 }; }; +template<> struct SubentityVertexMap< Wedge, Edge, 2, 1> { enum { index = 0 }; }; + +template<> struct SubentityVertexMap< Wedge, Edge, 3, 0> { enum { index = 3 }; }; +template<> struct SubentityVertexMap< Wedge, Edge, 3, 1> { enum { index = 4 }; }; + +template<> struct SubentityVertexMap< Wedge, Edge, 4, 0> { enum { index = 4 }; }; +template<> struct SubentityVertexMap< Wedge, Edge, 4, 1> { enum { index = 5 }; }; + +template<> struct SubentityVertexMap< Wedge, Edge, 5, 0> { enum { index = 5 }; }; +template<> struct SubentityVertexMap< Wedge, Edge, 5, 1> { enum { index = 3 }; }; + +template<> struct SubentityVertexMap< Wedge, Edge, 6, 0> { enum { index = 3 }; }; +template<> struct SubentityVertexMap< Wedge, Edge, 6, 1> { enum { index = 0 }; }; + +template<> struct SubentityVertexMap< Wedge, Edge, 7, 0> { enum { index = 5 }; }; +template<> struct SubentityVertexMap< Wedge, Edge, 7, 1> { enum { index = 2 }; }; + +template<> struct SubentityVertexMap< Wedge, Edge, 8, 0> { enum { index = 4 }; }; +template<> struct SubentityVertexMap< Wedge, Edge, 8, 1> { enum { index = 1 }; }; + + +template <> +struct SubentityVertexCount< Wedge, Polygon, 0 > +{ + static constexpr int count = 3; +}; + +template<> struct SubentityVertexMap< Wedge, Polygon, 0, 0> { enum { index = 0 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 0, 1> { enum { index = 1 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 0, 2> { enum { index = 2 }; }; + +template <> +struct SubentityVertexCount< Wedge, Polygon, 1 > +{ + static constexpr int count = 3; +}; + +template<> struct SubentityVertexMap< Wedge, Polygon, 1, 0> { enum { index = 3 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 1, 1> { enum { index = 4 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 1, 2> { enum { index = 5 }; }; + +template <> +struct SubentityVertexCount< Wedge, Polygon, 2 > +{ + static constexpr int count = 4; +}; + +template<> struct SubentityVertexMap< Wedge, Polygon, 2, 0> { enum { index = 3 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 2, 1> { enum { index = 0 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 2, 2> { enum { index = 2 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 2, 3> { enum { index = 5 }; }; + +template <> +struct SubentityVertexCount< Wedge, Polygon, 3 > +{ + static constexpr int count = 4; +}; + +template<> struct SubentityVertexMap< Wedge, Polygon, 3, 0> { enum { index = 4 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 3, 1> { enum { index = 1 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 3, 2> { enum { index = 2 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 3, 3> { enum { index = 5 }; }; + +template <> +struct SubentityVertexCount< Wedge, Polygon, 4 > +{ + static constexpr int count = 4; +}; + +template<> struct SubentityVertexMap< Wedge, Polygon, 4, 0> { enum { index = 3 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 4, 1> { enum { index = 0 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 4, 2> { enum { index = 1 }; }; +template<> struct SubentityVertexMap< Wedge, Polygon, 4, 3> { enum { index = 4 }; }; + +} // namespace Topologies +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/TypeResolver/BuildConfigTags.h b/src/TNL/Meshes/TypeResolver/BuildConfigTags.h index dd83a017af9e440fbb6a5fb463f9264945da4449..413e7538ada983726c23d002813e2431cff93988 100644 --- a/src/TNL/Meshes/TypeResolver/BuildConfigTags.h +++ b/src/TNL/Meshes/TypeResolver/BuildConfigTags.h @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include namespace TNL { namespace Meshes { @@ -84,6 +87,10 @@ template< typename ConfigTag, typename CellTopology > struct MeshCellTopologyTag //template< typename ConfigTag > struct MeshCellTopologyTag< ConfigTag, Topologies::Quadrangle > { enum { enabled = true }; }; //template< typename ConfigTag > struct MeshCellTopologyTag< ConfigTag, Topologies::Tetrahedron > { enum { enabled = true }; }; //template< typename ConfigTag > struct MeshCellTopologyTag< ConfigTag, Topologies::Hexahedron > { enum { enabled = true }; }; +//template< typename ConfigTag > struct MeshCellTopologyTag< ConfigTag, Topologies::Polygon > { enum { enabled = true }; }; +//template< typename ConfigTag > struct MeshCellTopologyTag< ConfigTag, Topologies::Wedge > { enum { enabled = true }; }; +//template< typename ConfigTag > struct MeshCellTopologyTag< ConfigTag, Topologies::Pyramid > { enum { enabled = true }; }; +//template< typename ConfigTag > struct MeshCellTopologyTag< ConfigTag, Topologies::Polyhedron > { enum { enabled = true }; }; // TODO: Simplex has not been tested yet //template< typename ConfigTag > struct MeshCellTopologyTag< ConfigTag, Topologies::Simplex > { enum { enabled = true }; }; diff --git a/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp b/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp index 72d3c8ef7102e847284c7cab880a29f810843e6f..f6c991f41dde3692e0285262a38cd161a39dc678 100644 --- a/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp +++ b/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp @@ -51,6 +51,14 @@ resolveCellTopology( Reader& reader, Functor&& functor ) return resolveSpaceDimension< Topologies::Tetrahedron >( reader, std::forward(functor) ); case VTK::EntityShape::Hexahedron: return resolveSpaceDimension< Topologies::Hexahedron >( reader, std::forward(functor) ); + case VTK::EntityShape::Polygon: + return resolveSpaceDimension< Topologies::Polygon >( reader, std::forward(functor) ); + case VTK::EntityShape::Wedge: + return resolveSpaceDimension< Topologies::Wedge >( reader, std::forward(functor) ); + case VTK::EntityShape::Pyramid: + return resolveSpaceDimension< Topologies::Pyramid >( reader, std::forward(functor) ); + case VTK::EntityShape::Polyhedron: + return resolveSpaceDimension< Topologies::Polyhedron >( reader, std::forward(functor) ); default: std::cerr << "unsupported cell topology: " << VTK::getShapeName( reader.getCellShape() ) << std::endl; return false; diff --git a/src/TNL/Meshes/VTKTraits.h b/src/TNL/Meshes/VTKTraits.h index 143654f71461ffa3b046a0d96f9c594e84f5e9ee..9f9de20ba1fd01defa0f5fc702f7d1b59433de37 100644 --- a/src/TNL/Meshes/VTKTraits.h +++ b/src/TNL/Meshes/VTKTraits.h @@ -19,6 +19,10 @@ #include #include #include +#include +#include +#include +#include namespace TNL { namespace Meshes { @@ -58,7 +62,8 @@ enum class EntityShape Voxel = 11, Hexahedron = 12, Wedge = 13, - Pyramid = 14 + Pyramid = 14, + Polyhedron = 100 }; inline std::string getShapeName( EntityShape shape ) @@ -93,6 +98,8 @@ inline std::string getShapeName( EntityShape shape ) return "Wedge"; case EntityShape::Pyramid: return "Pyramid"; + case EntityShape::Polyhedron: + return "Polyhedron"; } return ""; } @@ -115,6 +122,7 @@ inline int getEntityDimension( EntityShape shape ) case EntityShape::Hexahedron: return 3; case EntityShape::Wedge: return 3; case EntityShape::Pyramid: return 3; + case EntityShape::Polyhedron: return 3; } // this can actually happen when an invalid uint8_t value is converted to EntityShape throw std::runtime_error( "VTK::getEntityDimension: invalid entity shape value " + std::to_string(int(shape)) ); @@ -122,12 +130,16 @@ inline int getEntityDimension( EntityShape shape ) // static mapping of TNL entity topologies to EntityShape template< typename Topology > struct TopologyToEntityShape {}; -template<> struct TopologyToEntityShape< Topologies::Vertex > { static constexpr EntityShape shape = EntityShape::Vertex; }; -template<> struct TopologyToEntityShape< Topologies::Edge > { static constexpr EntityShape shape = EntityShape::Line; }; -template<> struct TopologyToEntityShape< Topologies::Triangle > { static constexpr EntityShape shape = EntityShape::Triangle; }; -template<> struct TopologyToEntityShape< Topologies::Quadrangle > { static constexpr EntityShape shape = EntityShape::Quad; }; -template<> struct TopologyToEntityShape< Topologies::Tetrahedron > { static constexpr EntityShape shape = EntityShape::Tetra; }; -template<> struct TopologyToEntityShape< Topologies::Hexahedron > { static constexpr EntityShape shape = EntityShape::Hexahedron; }; +template<> struct TopologyToEntityShape< Topologies::Vertex > { static constexpr EntityShape shape = EntityShape::Vertex; }; +template<> struct TopologyToEntityShape< Topologies::Edge > { static constexpr EntityShape shape = EntityShape::Line; }; +template<> struct TopologyToEntityShape< Topologies::Triangle > { static constexpr EntityShape shape = EntityShape::Triangle; }; +template<> struct TopologyToEntityShape< Topologies::Polygon > { static constexpr EntityShape shape = EntityShape::Polygon; }; +template<> struct TopologyToEntityShape< Topologies::Quadrangle > { static constexpr EntityShape shape = EntityShape::Quad; }; +template<> struct TopologyToEntityShape< Topologies::Tetrahedron > { static constexpr EntityShape shape = EntityShape::Tetra; }; +template<> struct TopologyToEntityShape< Topologies::Hexahedron > { static constexpr EntityShape shape = EntityShape::Hexahedron; }; +template<> struct TopologyToEntityShape< Topologies::Wedge > { static constexpr EntityShape shape = EntityShape::Wedge; }; +template<> struct TopologyToEntityShape< Topologies::Pyramid > { static constexpr EntityShape shape = EntityShape::Pyramid; }; +template<> struct TopologyToEntityShape< Topologies::Polyhedron > { static constexpr EntityShape shape = EntityShape::Polyhedron; }; // mapping used in VTKWriter template< typename GridEntity > diff --git a/src/TNL/Meshes/Writers/EntitiesListSize.h b/src/TNL/Meshes/Writers/EntitiesListSize.h new file mode 100644 index 0000000000000000000000000000000000000000..15e13d9d9f88c2764ba28a7e32bf46c3e4a752a3 --- /dev/null +++ b/src/TNL/Meshes/Writers/EntitiesListSize.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +namespace TNL { +namespace Meshes { +namespace Writers { + +template< typename Mesh, + int EntityDimension, + typename EntityType = typename Mesh::template EntityType< EntityDimension > + > +struct EntitiesListSize +{ + using IndexType = typename Mesh::GlobalIndexType; + + static IndexType getSize( const Mesh& mesh ) + { + IndexType entitiesCount = mesh.template getEntitiesCount< EntityType >(); + IndexType verticesPerEntity = VerticesPerEntity< EntityType >::count; + return entitiesCount * ( verticesPerEntity + 1 ); + } +}; + +template< typename Mesh, + int EntityDimension, + typename MeshConfig, + typename Device > +struct EntitiesListSize< Mesh, EntityDimension, MeshEntity< MeshConfig, Device, Topologies::Polygon > > +{ + using IndexType = typename Mesh::GlobalIndexType; + + static IndexType getSize( const Mesh& mesh ) + { + IndexType entitiesCount = mesh.template getEntitiesCount< EntityDimension >(); + IndexType entitiesListSize = entitiesCount; + for(IndexType index = 0; index < entitiesCount; index++) + entitiesListSize += mesh.template getSubentitiesCount< EntityDimension, 0 >( index ); + return entitiesListSize; + } +}; + +} // namespace Writers +} // namespace Meshes +} // namespace TNL diff --git a/src/TNL/Meshes/Writers/FPMAWriter.h b/src/TNL/Meshes/Writers/FPMAWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..19f6a7dc59028775d044c74eca48ccfbf8911541 --- /dev/null +++ b/src/TNL/Meshes/Writers/FPMAWriter.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +namespace TNL { +namespace Meshes { +//! \brief Namespace for mesh writers. +namespace Writers { + +namespace details { + +template< typename Mesh, int EntityDimension, int SubDimension > struct MeshEntitiesFPMAWriter; + +} // namespace details + +template< typename Mesh > +class FPMAWriter +{ + static_assert( std::is_same< typename Mesh::Cell::EntityTopology, Topologies::Polyhedron >::value, "The FPMA format supports polyhedral meshes." ); + + template< int EntityDimension, int SubDimension > + using EntitiesWriter = details::MeshEntitiesFPMAWriter< Mesh, EntityDimension, SubDimension >; + +public: + using IndexType = typename Mesh::GlobalIndexType; + + FPMAWriter() = delete; + + FPMAWriter( std::ostream& str ) + : str(str.rdbuf()) + { + } + + void writeEntities( const Mesh& mesh ); + +protected: + void writePoints( const Mesh& mesh ); + + std::ostream str; + + // number of cells written to the file + //IndexType cellsCount = 0; + + // number of faces written to the file + //IndexType facesCount = 0; + + // number of points written to the file + //IndexType pointsCount = 0; +}; + +} // namespace Writers +} // namespace Meshes +} // namespace TNL + +#include diff --git a/src/TNL/Meshes/Writers/FPMAWriter.hpp b/src/TNL/Meshes/Writers/FPMAWriter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..99ecb0ab091e3a7cfb5e6c02a8cdfffe33f478bc --- /dev/null +++ b/src/TNL/Meshes/Writers/FPMAWriter.hpp @@ -0,0 +1,87 @@ +/*************************************************************************** + VTKWriter.hpp - 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 + +#include + +namespace TNL { +namespace Meshes { +namespace Writers { + +namespace details { + +inline void +writeInt( std::ostream& str, std::int32_t value ) +{ + str << value << ' '; +} + +template< typename Real > +void +writeReal( std::ostream& str, const Real value ) +{ + str.precision( std::numeric_limits< Real >::digits10 ); + str << value << ' '; +} + +template< typename Mesh, + int EntityDimension, + int SubDimension > +struct MeshEntitiesFPMAWriter +{ + static void exec( const Mesh& mesh, std::ostream& str ) + { + using Index = typename Mesh::GlobalIndexType; + + const Index entitiesCount = mesh.template getEntitiesCount< EntityDimension >(); + str << '\n' << entitiesCount; + for( Index i = 0; i < entitiesCount; i++ ) { + str << '\n'; + const auto& entity = mesh.template getEntity< EntityDimension >( i ); + const Index subentitiesPerEntity = entity.template getSubentitiesCount< SubDimension >(); + writeInt( str, subentitiesPerEntity ); + for( Index j = 0; j < subentitiesPerEntity; j++ ) + writeInt( str, entity.template getSubentityIndex< SubDimension >( j ) ); + } + } +}; + +} // namespace details + +template< typename Mesh > +void +FPMAWriter< Mesh >::writeEntities( const Mesh& mesh ) +{ + writePoints( mesh ); + EntitiesWriter< 2, 0 >::exec( mesh, str ); + EntitiesWriter< 3, 2 >::exec( mesh, str ); +} + + +template< typename Mesh > +void +FPMAWriter< Mesh >::writePoints( const Mesh& mesh ) +{ + IndexType pointsCount = mesh.template getEntitiesCount< 0 >(); + str << pointsCount << '\n'; + for( IndexType i = 0; i < pointsCount; i++ ) { + const auto& vertex = mesh.template getEntity< 0 >( i ); + const auto& point = vertex.getPoint(); + for( IndexType j = 0; j < point.getSize(); j++ ) + details::writeReal( str, point[ j ] ); + } +} + +} // namespace Writers +} // namespace Meshes +} // namespace TNL diff --git a/src/TNL/Meshes/Writers/VTKWriter.hpp b/src/TNL/Meshes/Writers/VTKWriter.hpp index 87b7950813cde6e7a2811962789e06c8c9faa677..ada849aefc9b8726fcd8171e0d2de99dab328420 100644 --- a/src/TNL/Meshes/Writers/VTKWriter.hpp +++ b/src/TNL/Meshes/Writers/VTKWriter.hpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -62,9 +63,9 @@ struct MeshEntitiesVTKWriter using Index = typename Mesh::GlobalIndexType; const Index entitiesCount = mesh.template getEntitiesCount< EntityType >(); - const int verticesPerEntity = VerticesPerEntity< EntityType >::count;; for( Index i = 0; i < entitiesCount; i++ ) { const auto& entity = mesh.template getEntity< EntityType >( i ); + const int verticesPerEntity = entity.template getSubentitiesCount< 0 >(); writeInt( format, str, verticesPerEntity ); for( int j = 0; j < verticesPerEntity; j++ ) writeInt( format, str, entity.template getSubentityIndex< 0 >( j ) ); @@ -442,8 +443,7 @@ VTKWriter< Mesh >::writeEntities( const Mesh& mesh ) using EntityType = typename Mesh::template EntityType< EntityDimension >; cellsCount = mesh.template getEntitiesCount< EntityType >(); - const int verticesPerEntity = VerticesPerEntity< EntityType >::count; - const std::uint64_t cellsListSize = cellsCount * ( verticesPerEntity + 1 ); + const std::uint64_t cellsListSize = EntitiesListSize< Mesh, EntityDimension >::getSize( mesh ); str << std::endl << "CELLS " << cellsCount << " " << cellsListSize << std::endl; EntitiesWriter< EntityDimension >::exec( mesh, str, format ); diff --git a/src/TNL/Meshes/Writers/VTUWriter.hpp b/src/TNL/Meshes/Writers/VTUWriter.hpp index e26b2942aeb44b7315d82effd43d6b48a362bb87..385537a521bc1d8a2cd0147ee27632d6849f39de 100644 --- a/src/TNL/Meshes/Writers/VTUWriter.hpp +++ b/src/TNL/Meshes/Writers/VTUWriter.hpp @@ -43,9 +43,9 @@ struct MeshEntitiesVTUCollector 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 ); + const Index verticesPerEntity = entity.template getSubentitiesCount< 0 >(); for( Index j = 0; j < verticesPerEntity; j++ ) connectivity.push_back( entity.template getSubentityIndex< 0 >( j ) ); offsets.push_back( connectivity.size() ); diff --git a/src/TNL/TypeTraits.h b/src/TNL/TypeTraits.h index 8abb28c6af048a6ef3be17c356c3ed96bb3558af..31505dd78fa35a9ff9b0a14cc7e2ebe4536987d4 100644 --- a/src/TNL/TypeTraits.h +++ b/src/TNL/TypeTraits.h @@ -295,4 +295,21 @@ struct copy_const }; }; +/** + * \brief Type trait for checking if T has count member + */ +template< typename T > +class HasCountMember +{ +private: + typedef char YesType[1]; + typedef char NoType[2]; + + template< typename C > static YesType& test( decltype( &C::count ) ); + template< typename C > static NoType& test(...); + +public: + static constexpr bool value = ( sizeof( test< std::decay_t >(0) ) == sizeof( YesType ) ); +}; + } //namespace TNL diff --git a/src/Tools/CMakeLists.txt b/src/Tools/CMakeLists.txt index 84a05dd9ca25620402d48d35b5981841025895ad..8af2438fdf675656e6c89d7b51d9152d8bb4890e 100644 --- a/src/Tools/CMakeLists.txt +++ b/src/Tools/CMakeLists.txt @@ -4,6 +4,8 @@ ADD_EXECUTABLE(tnl-decompose-grid tnl-decompose-grid.cpp ) ADD_EXECUTABLE(tnl-grid-setup tnl-grid-setup.cpp ) ADD_EXECUTABLE(tnl-grid-to-mesh tnl-grid-to-mesh.cpp ) ADD_EXECUTABLE(tnl-mesh-converter tnl-mesh-converter.cpp ) +ADD_EXECUTABLE(tnl-triangulate-mesh tnl-triangulate-mesh.cpp ) +ADD_EXECUTABLE(tnl-planar-correct-mesh tnl-planar-correct-mesh.cpp ) ADD_EXECUTABLE(tnl-game-of-life tnl-game-of-life.cpp ) if( BUILD_CUDA ) CUDA_ADD_EXECUTABLE(tnl-test-distributed-mesh tnl-test-distributed-mesh.cu ) @@ -28,7 +30,7 @@ endif() find_package( ZLIB ) if( ZLIB_FOUND ) - foreach( target IN ITEMS tnl-init tnl-diff tnl-decompose-grid tnl-grid-to-mesh tnl-mesh-converter tnl-game-of-life tnl-test-distributed-mesh ) + foreach( target IN ITEMS tnl-init tnl-diff tnl-decompose-grid tnl-grid-to-mesh tnl-mesh-converter tnl-triangulate-mesh tnl-planar-correct-mesh tnl-game-of-life tnl-test-distributed-mesh ) target_compile_definitions(${target} PUBLIC "-DHAVE_ZLIB") target_include_directories(${target} PUBLIC ${ZLIB_INCLUDE_DIRS}) target_link_libraries(${target} ${ZLIB_LIBRARIES}) @@ -37,7 +39,7 @@ endif() find_package( tinyxml2 QUIET ) if( tinyxml2_FOUND ) - foreach( target IN ITEMS tnl-init tnl-diff tnl-decompose-grid tnl-grid-to-mesh tnl-mesh-converter tnl-game-of-life tnl-test-distributed-mesh ) + foreach( target IN ITEMS tnl-init tnl-diff tnl-decompose-grid tnl-grid-to-mesh tnl-mesh-converter tnl-triangulate-mesh tnl-planar-correct-mesh tnl-game-of-life tnl-test-distributed-mesh ) target_compile_definitions(${target} PUBLIC "-DHAVE_TINYXML2") target_link_libraries(${target} tinyxml2::tinyxml2) endforeach() @@ -72,6 +74,8 @@ INSTALL( TARGETS tnl-init tnl-grid-setup tnl-grid-to-mesh tnl-mesh-converter + tnl-triangulate-mesh + tnl-planar-correct-mesh tnl-game-of-life tnl-test-distributed-mesh tnl-dicom-reader diff --git a/src/Tools/tnl-decompose-mesh.cpp b/src/Tools/tnl-decompose-mesh.cpp index 39612729b9585bdfac4386250b707e4f22402cbf..97383e9f3791af5ff52b88739b23deb2a2a266b0 100644 --- a/src/Tools/tnl-decompose-mesh.cpp +++ b/src/Tools/tnl-decompose-mesh.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -522,22 +523,16 @@ decompose_and_save( const Mesh& mesh, } vertex_global_to_local.clear(); - // copy cell seeds into a TNL array which is used by the mesh initializer - using CellSeedArrayType = typename Mesh::MeshTraitsType::CellSeedArrayType; - CellSeedArrayType cellSeeds = seeds; - seeds.clear(); - seeds.shrink_to_fit(); - // create "GlobalIndex" CellData array IndexArray cellsGlobalIndices = seeds_global_indices; seeds_global_indices.clear(); seeds_global_indices.shrink_to_fit(); // create "vtkGhostType" CellData and PointData arrays - see https://blog.kitware.com/ghost-and-blanking-visibility-changes/ - Containers::Array< std::uint8_t, Devices::Sequential, Index > cellGhosts( cellSeeds.getSize() ), pointGhosts( points.getSize() ); + Containers::Array< std::uint8_t, Devices::Sequential, Index > cellGhosts( seeds.size() ), pointGhosts( points.getSize() ); for( Index i = 0; i < cells_counts[ p ]; i++ ) cellGhosts[ i ] = 0; - for( Index i = cells_counts[ p ]; i < cellSeeds.getSize(); i++ ) + for( Index i = cells_counts[ p ]; i < (Index) seeds.size(); i++ ) cellGhosts[ i ] = (std::uint8_t) Meshes::VTK::CellGhostTypes::DUPLICATECELL; // point ghosts are more tricky because they were assigned to the subdomain with higher number Index pointsGhostCount = 0; @@ -577,20 +572,35 @@ decompose_and_save( const Mesh& mesh, PermutationApplier::permuteArray( pointsGlobalIndices, perm ); // - points PermutationApplier::permuteArray( points, perm ); - // - cellSeeds.setCornerID (inverse perm) + // - seeds.setCornerID (inverse perm) std::vector< Index > iperm( points.getSize() ); for( Index i = 0; i < perm.getSize(); i++ ) iperm[ perm[ i ] ] = i; - for( Index i = 0; i < cellSeeds.getSize(); i++ ) { - auto& cornerIds = cellSeeds[ i ].getCornerIds(); + for( auto& seed : seeds ) { + auto& cornerIds = seed.getCornerIds(); for( Index v = 0; v < cornerIds.getSize(); v++ ) cornerIds[ v ] = iperm[ cornerIds[ v ] ]; } } + // copy points and cell seeds to the MeshBuilder + TNL::Meshes::MeshBuilder< Mesh > builder; + builder.setEntitiesCount( points.getSize(), seeds.size() ); + for( Index i = 0; i < points.getSize(); i++ ) + builder.setPoint( i, points[ i ] ); + points.reset(); + for( std::size_t i = 0; i < seeds.size(); i++ ) { + const auto& cornerIds = seeds[ i ].getCornerIds(); + for( Index v = 0; v < cornerIds.getSize(); v++ ) + builder.getCellSeed( i ).setCornerId( v, cornerIds[ v ] ); + } + seeds.clear(); + seeds.shrink_to_fit(); + // init mesh for the subdomain Mesh subdomain; - subdomain.init( points, cellSeeds ); + if( ! builder.build( subdomain ) ) + throw std::runtime_error( "mesh builder failed for subdomain " + std::to_string(p) ); // write the subdomain using Writer = Meshes::Writers::VTUWriter< Mesh >; diff --git a/src/Tools/tnl-grid-to-mesh.cpp b/src/Tools/tnl-grid-to-mesh.cpp index e2d255eb06376a4e397569b24bfbb84810d78152..193f606206644340fecb791ca1d4df3bb25ae0d8 100644 --- a/src/Tools/tnl-grid-to-mesh.cpp +++ b/src/Tools/tnl-grid-to-mesh.cpp @@ -75,8 +75,7 @@ struct MeshCreator< Meshes::Grid< 1, Real, Device, Index > > const Index numberOfCells = grid.template getEntitiesCount< typename GridType::Cell >(); Meshes::MeshBuilder< MeshType > meshBuilder; - meshBuilder.setPointsCount( numberOfVertices ); - meshBuilder.setCellsCount( numberOfCells ); + meshBuilder.setEntitiesCount( numberOfVertices, numberOfCells ); for( Index i = 0; i < numberOfVertices; i++ ) { const auto vertex = grid.template getEntity< typename GridType::Vertex >( i ); @@ -113,8 +112,7 @@ struct MeshCreator< Meshes::Grid< 2, Real, Device, Index > > const Index numberOfCells = grid.template getEntitiesCount< typename GridType::Cell >(); Meshes::MeshBuilder< MeshType > meshBuilder; - meshBuilder.setPointsCount( numberOfVertices ); - meshBuilder.setCellsCount( numberOfCells ); + meshBuilder.setEntitiesCount( numberOfVertices, numberOfCells ); for( Index i = 0; i < numberOfVertices; i++ ) { const auto vertex = grid.template getEntity< typename GridType::Vertex >( i ); @@ -152,8 +150,7 @@ struct MeshCreator< Meshes::Grid< 3, Real, Device, Index > > const Index numberOfCells = grid.template getEntitiesCount< typename GridType::Cell >(); Meshes::MeshBuilder< MeshType > meshBuilder; - meshBuilder.setPointsCount( numberOfVertices ); - meshBuilder.setCellsCount( numberOfCells ); + meshBuilder.setEntitiesCount( numberOfVertices, numberOfCells ); for( Index i = 0; i < numberOfVertices; i++ ) { const auto vertex = grid.template getEntity< typename GridType::Vertex >( i ); diff --git a/src/Tools/tnl-mesh-converter.cpp b/src/Tools/tnl-mesh-converter.cpp index bbaf821757191456a500a090e946ce98c536c67c..b97639118b740e8db9169c872ca44d6706d225e3 100644 --- a/src/Tools/tnl-mesh-converter.cpp +++ b/src/Tools/tnl-mesh-converter.cpp @@ -41,8 +41,11 @@ template<> struct GridIndexTag< MeshConverterConfigTag, long int >{ enum { enabl template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Edge > { enum { enabled = true }; }; template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Triangle > { enum { enabled = true }; }; template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Quadrangle > { enum { enabled = true }; }; +template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Polygon > { enum { enabled = true }; }; template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Tetrahedron > { enum { enabled = true }; }; template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Hexahedron > { enum { enabled = true }; }; +template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Wedge > { enum { enabled = true }; }; +template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Pyramid > { enum { enabled = true }; }; // Meshes are enabled only for the space dimension equal to the cell dimension. template< typename CellTopology, int SpaceDimension > diff --git a/src/Tools/tnl-planar-correct-mesh.cpp b/src/Tools/tnl-planar-correct-mesh.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4802b66ada8ee204cca6c25bf75c5756a53612c --- /dev/null +++ b/src/Tools/tnl-planar-correct-mesh.cpp @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include + +using namespace TNL; + +struct MeshPlanarCorrectConfigTag {}; + +namespace TNL { +namespace Meshes { +namespace BuildConfigTags { + +/**** + * Turn off all grids. + */ +template<> struct GridRealTag< MeshPlanarCorrectConfigTag, float > { enum { enabled = false }; }; +template<> struct GridRealTag< MeshPlanarCorrectConfigTag, double > { enum { enabled = false }; }; +template<> struct GridRealTag< MeshPlanarCorrectConfigTag, long double > { enum { enabled = false }; }; + +/**** + * Unstructured meshes. + */ +template<> struct MeshCellTopologyTag< MeshPlanarCorrectConfigTag, Topologies::Polygon > { enum { enabled = true }; }; +template<> struct MeshCellTopologyTag< MeshPlanarCorrectConfigTag, Topologies::Polyhedron > { enum { enabled = true }; }; + +// Meshes are enabled only for the space dimension equal to 3 +template< typename CellTopology, int SpaceDimension > +struct MeshSpaceDimensionTag< MeshPlanarCorrectConfigTag, CellTopology, SpaceDimension > +{ enum { enabled = ( SpaceDimension == 3 ) }; }; + +// Meshes are enabled only for types explicitly listed below. +template<> struct MeshRealTag< MeshPlanarCorrectConfigTag, float > { enum { enabled = true }; }; +template<> struct MeshRealTag< MeshPlanarCorrectConfigTag, double > { enum { enabled = true }; }; +template<> struct MeshGlobalIndexTag< MeshPlanarCorrectConfigTag, long int > { enum { enabled = true }; }; +template<> struct MeshGlobalIndexTag< MeshPlanarCorrectConfigTag, int > { enum { enabled = true }; }; +template<> struct MeshLocalIndexTag< MeshPlanarCorrectConfigTag, short int > { enum { enabled = true }; }; + +// Config tag specifying the MeshConfig template to use. +template<> +struct MeshConfigTemplateTag< MeshPlanarCorrectConfigTag > +{ + template< typename Cell, + int SpaceDimension = Cell::dimension, + typename Real = float, + typename GlobalIndex = int, + typename LocalIndex = short int > + struct MeshConfig + { + using CellTopology = Cell; + using RealType = Real; + using GlobalIndexType = GlobalIndex; + using LocalIndexType = LocalIndex; + + static constexpr int spaceDimension = SpaceDimension; + static constexpr int meshDimension = Cell::dimension; + + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) + { + return (subentityDimension == 0 && entityDimension == meshDimension) + || (subentityDimension == meshDimension - 1 && entityDimension == meshDimension ) + || (subentityDimension == 0 && entityDimension == meshDimension - 1 ); + } + + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) + { + return false; + } + + static constexpr bool entityTagsStorage( int entityDimension ) + { + return false; + } + + static constexpr bool dualGraphStorage() + { + return false; + } + }; +}; + +} // namespace BuildConfigTags +} // namespace Meshes +} // namespace TNL + +using namespace TNL::Meshes; + +template< typename Mesh > +auto getPlanarMeshHelper( const Mesh& mesh, const String& decompositionType ) +{ + using namespace TNL::Meshes; + + if( decompositionType[0] == 'c' ) { + return getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + } + else { // decompositionType[0] == 'p' + return getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + } +} + +template< typename Topology > +struct PlanarMeshWriter; + +template<> +struct PlanarMeshWriter< Topologies::Polygon > +{ + template< typename Mesh > + static void exec( const Mesh& mesh, const String& outputFileName ) + { + using Writer = Meshes::Writers::VTKWriter< Mesh >; + std::ofstream file( outputFileName ); + Writer writer( file ); + writer.template writeEntities< Mesh::getMeshDimension() >( mesh ); + } +}; + +template<> +struct PlanarMeshWriter< Topologies::Polyhedron > +{ + template< typename Mesh > + static void exec( const Mesh& mesh, const String& outputFileName ) + { + using Writer = Meshes::Writers::FPMAWriter< Mesh >; + std::ofstream file( outputFileName ); + Writer writer( file ); + writer.writeEntities( mesh ); + } +}; + +template< typename Mesh > +bool triangulateMesh( const Mesh& mesh, const String& outputFileName, const String& decompositionType ) +{ + const auto planarMesh = getPlanarMeshHelper( mesh, decompositionType ); + using PlanarMesh = decltype( planarMesh ); + using CellTopology = typename PlanarMesh::Cell::EntityTopology; + PlanarMeshWriter< CellTopology >::exec( planarMesh, outputFileName ); + return true; +} + +void configSetup( Config::ConfigDescription& config ) +{ + config.addDelimiter( "General settings:" ); + config.addRequiredEntry< String >( "input-file", "Input file with the mesh." ); + config.addRequiredEntry< String >( "output-file", "Output mesh file path." ); + config.addRequiredEntry< String >( "decomposition-type", "Type of decomposition to use for non-planar polygons." ); + config.addEntryEnum( "c" ); + config.addEntryEnum( "p" ); +} + +int main( int argc, char* argv[] ) +{ + Config::ParameterContainer parameters; + Config::ConfigDescription conf_desc; + + configSetup( conf_desc ); + + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) + return EXIT_FAILURE; + + const String inputFileName = parameters.getParameter< String >( "input-file" ); + const String inputFileFormat = "auto"; + const String outputFileName = parameters.getParameter< String >( "output-file" ); + const String decompositionType = parameters.getParameter< String >( "decomposition-type" ); + + auto wrapper = [&] ( auto& reader, auto&& mesh ) -> bool + { + return triangulateMesh( mesh, outputFileName, decompositionType ); + }; + return ! Meshes::resolveAndLoadMesh< MeshPlanarCorrectConfigTag, Devices::Host >( wrapper, inputFileName, inputFileFormat ); +} diff --git a/src/Tools/tnl-triangulate-mesh.cpp b/src/Tools/tnl-triangulate-mesh.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c83b97944ae3fd01f9387ed21643457795ab746 --- /dev/null +++ b/src/Tools/tnl-triangulate-mesh.cpp @@ -0,0 +1,176 @@ +#include +#include +#include +#include +#include + +using namespace TNL; + +struct MeshTriangulatorConfigTag {}; + +namespace TNL { +namespace Meshes { +namespace BuildConfigTags { + +/**** + * Turn off all grids. + */ +template<> struct GridRealTag< MeshTriangulatorConfigTag, float > { enum { enabled = false }; }; +template<> struct GridRealTag< MeshTriangulatorConfigTag, double > { enum { enabled = false }; }; +template<> struct GridRealTag< MeshTriangulatorConfigTag, long double > { enum { enabled = false }; }; + +/**** + * Unstructured meshes. + */ +template<> struct MeshCellTopologyTag< MeshTriangulatorConfigTag, Topologies::Polygon > { enum { enabled = true }; }; +template<> struct MeshCellTopologyTag< MeshTriangulatorConfigTag, Topologies::Polyhedron > { enum { enabled = true }; }; + +// Meshes are enabled only for the space dimension equal to the cell dimension. +template< typename CellTopology, int SpaceDimension > +struct MeshSpaceDimensionTag< MeshTriangulatorConfigTag, CellTopology, SpaceDimension > +{ enum { enabled = ( SpaceDimension == CellTopology::dimension ) }; }; + +// Polygonal Meshes are enable for the space dimension equal to 2 or 3 +template< int SpaceDimension > +struct MeshSpaceDimensionTag< MeshTriangulatorConfigTag, Topologies::Polygon, SpaceDimension > +{ enum { enabled = ( SpaceDimension >= 2 && SpaceDimension <= 3 ) }; }; + +// Meshes are enabled only for types explicitly listed below. +template<> struct MeshRealTag< MeshTriangulatorConfigTag, float > { enum { enabled = true }; }; +template<> struct MeshRealTag< MeshTriangulatorConfigTag, double > { enum { enabled = true }; }; +template<> struct MeshGlobalIndexTag< MeshTriangulatorConfigTag, long int > { enum { enabled = true }; }; +template<> struct MeshGlobalIndexTag< MeshTriangulatorConfigTag, int > { enum { enabled = true }; }; +template<> struct MeshLocalIndexTag< MeshTriangulatorConfigTag, short int > { enum { enabled = true }; }; + +// Config tag specifying the MeshConfig template to use. +template<> +struct MeshConfigTemplateTag< MeshTriangulatorConfigTag > +{ + template< typename Cell, + int SpaceDimension = Cell::dimension, + typename Real = float, + typename GlobalIndex = int, + typename LocalIndex = short int > + struct MeshConfig + { + using CellTopology = Cell; + using RealType = Real; + using GlobalIndexType = GlobalIndex; + using LocalIndexType = LocalIndex; + + static constexpr int spaceDimension = SpaceDimension; + static constexpr int meshDimension = Cell::dimension; + + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) + { + return (subentityDimension == 0 && entityDimension == meshDimension) + || (subentityDimension == meshDimension - 1 && entityDimension == meshDimension ) + || (subentityDimension == 0 && entityDimension == meshDimension - 1 ); + } + + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) + { + return false; + } + + static constexpr bool entityTagsStorage( int entityDimension ) + { + return false; + } + + static constexpr bool dualGraphStorage() + { + return false; + } + }; +}; + +} // namespace BuildConfigTags +} // namespace Meshes +} // namespace TNL + +template< typename Mesh > +auto getDecomposedMeshHelper( const Mesh& mesh, const String& decompositionType ) +{ + using namespace TNL::Meshes; + + if( decompositionType[0] == 'c' ) { + if( decompositionType[1] == 'c' ) { + return getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + } + else { // decompositionType[1] == 'p' + return getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + } + } + else { // decompositionType[0] == 'p' + if( decompositionType[1] == 'c' ) { + return getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + } + else { // decompositionType[1] == 'p' + return getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + } + } +} + +template< typename Mesh > +bool triangulateMesh( const Mesh& mesh, const String& outputFileName, const String& outputFormat, const String& decompositionType ) +{ + const auto decomposedMesh = getDecomposedMeshHelper( mesh, decompositionType ); + + if( outputFormat == "vtk" ) { + using Writer = Meshes::Writers::VTKWriter< decltype( decomposedMesh ) >; + std::ofstream file( outputFileName ); + Writer writer( file ); + writer.template writeEntities< Mesh::getMeshDimension() >( decomposedMesh ); + } + else if( outputFormat == "vtu" ) { + using Writer = Meshes::Writers::VTUWriter< decltype( decomposedMesh ) >; + std::ofstream file( outputFileName ); + Writer writer( file ); + writer.template writeEntities< Mesh::getMeshDimension() >( decomposedMesh ); + } + + return true; +} + +void configSetup( Config::ConfigDescription& config ) +{ + config.addDelimiter( "General settings:" ); + config.addRequiredEntry< String >( "input-file", "Input file with the mesh." ); + config.addRequiredEntry< String >( "output-file", "Output mesh file path." ); + config.addRequiredEntry< String >( "output-file-format", "Output mesh file format." ); + config.addEntryEnum( "vtk" ); + config.addEntryEnum( "vtu" ); + config.addRequiredEntry< String >( "decomposition-type", "Type of decomposition to use." ); + config.addEntryEnum( "cc" ); + config.addEntryEnum( "cp" ); + config.addEntryEnum( "pc" ); + config.addEntryEnum( "pp" ); +} + +int main( int argc, char* argv[] ) +{ + Config::ParameterContainer parameters; + Config::ConfigDescription conf_desc; + + configSetup( conf_desc ); + + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) + return EXIT_FAILURE; + + const String inputFileName = parameters.getParameter< String >( "input-file" ); + const String inputFileFormat = "auto"; + const String outputFileName = parameters.getParameter< String >( "output-file" ); + const String outputFileFormat = parameters.getParameter< String >( "output-file-format" ); + const String decompositionType = parameters.getParameter< String >( "decomposition-type" ); + + auto wrapper = [&] ( auto& reader, auto&& mesh ) -> bool + { + return triangulateMesh( mesh, outputFileName, outputFileFormat, decompositionType ); + }; + return ! Meshes::resolveAndLoadMesh< MeshTriangulatorConfigTag, Devices::Host >( wrapper, inputFileName, inputFileFormat ); +} diff --git a/src/UnitTests/Meshes/CMakeLists.txt b/src/UnitTests/Meshes/CMakeLists.txt index 86cb34d5c2d25bf35a8721ac0c215784ce805e1d..c8e71e9552977a7a4898d47a1f224fc2ceceac7a 100644 --- a/src/UnitTests/Meshes/CMakeLists.txt +++ b/src/UnitTests/Meshes/CMakeLists.txt @@ -21,6 +21,11 @@ if( ${BUILD_CUDA} AND ${CUDA_VERSION_MAJOR} GREATER_EQUAL 9 ) OPTIONS ${CUDA_TESTS_FLAGS} ) TARGET_LINK_LIBRARIES( MeshOrderingTest ${TESTS_LIBRARIES} ) target_link_options( MeshOrderingTest PRIVATE ${TESTS_LINKER_FLAGS} ) + + CUDA_ADD_EXECUTABLE( MeshGeometryTest MeshGeometryTest.cu + OPTIONS ${CUDA_TESTS_FLAGS} ) + TARGET_LINK_LIBRARIES( MeshGeometryTest ${TESTS_LIBRARIES} ) + target_link_options( MeshGeometryTest PRIVATE ${TESTS_LINKER_FLAGS} ) else() ADD_EXECUTABLE( MeshTest MeshTest.cpp ) TARGET_COMPILE_OPTIONS( MeshTest PRIVATE ${CXX_TESTS_FLAGS} ) @@ -36,20 +41,25 @@ else() TARGET_COMPILE_OPTIONS( MeshOrderingTest PRIVATE ${CXX_TESTS_FLAGS} ) TARGET_LINK_LIBRARIES( MeshOrderingTest ${TESTS_LIBRARIES} ) target_link_options( MeshOrderingTest PRIVATE ${TESTS_LINKER_FLAGS} ) + + ADD_EXECUTABLE( MeshGeometryTest MeshGeometryTest.cpp ) + TARGET_COMPILE_OPTIONS( MeshGeometryTest PRIVATE ${CXX_TESTS_FLAGS} ) + TARGET_LINK_LIBRARIES( MeshGeometryTest ${TESTS_LIBRARIES} ) + target_link_options( MeshGeometryTest PRIVATE ${TESTS_LINKER_FLAGS} ) endif() ADD_TEST( EntityTagsTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/EntityTagsTest${CMAKE_EXECUTABLE_SUFFIX} ) ADD_TEST( MeshTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MeshTest${CMAKE_EXECUTABLE_SUFFIX} ) ADD_TEST( MeshTraverserTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MeshTraverserTest${CMAKE_EXECUTABLE_SUFFIX} ) ADD_TEST( MeshOrderingTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MeshOrderingTest${CMAKE_EXECUTABLE_SUFFIX} ) - +ADD_TEST( MeshGeometryTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MeshGeometryTest${CMAKE_EXECUTABLE_SUFFIX} ) # special tests needing external libraries find_package( ZLIB ) find_package( tinyxml2 QUIET ) if( ZLIB_FOUND AND tinyxml2_FOUND ) - foreach( target IN ITEMS NetgenReaderTest VTKReaderTest VTUReaderTest VTIReaderTest ) + foreach( target IN ITEMS NetgenReaderTest VTKReaderTest VTUReaderTest VTIReaderTest FPMAReaderTest ) add_executable(${target} ${target}.cpp) target_compile_options(${target} PRIVATE ${CXX_TESTS_FLAGS} ) target_link_libraries(${target} ${TESTS_LIBRARIES}) diff --git a/src/UnitTests/Meshes/DistributedMeshes/DistributedMeshTest.h b/src/UnitTests/Meshes/DistributedMeshes/DistributedMeshTest.h index 18ed6b4bf0613a763e1ac57f18da3edf2103301d..570c59cbbe25d6c9412f290f9a5f08c388ad0c02 100644 --- a/src/UnitTests/Meshes/DistributedMeshes/DistributedMeshTest.h +++ b/src/UnitTests/Meshes/DistributedMeshes/DistributedMeshTest.h @@ -93,8 +93,7 @@ struct GridDistributor< TNL::Meshes::Grid< 2, Real, Device, Index > > for( Index x = cell_begin.x() - (rank_coordinates.x() > 0) * overlap; x < cell_end.x() + (rank_coordinates.x() < rank_sizes.x() - 1) * overlap; x++ ) cellsCount++; TNL::Meshes::MeshBuilder< LocalMeshType > meshBuilder; - meshBuilder.setPointsCount( verticesCount ); - meshBuilder.setCellsCount( cellsCount ); + meshBuilder.setEntitiesCount( verticesCount, cellsCount ); // mappings for vertex indices std::unordered_map< Index, Index > vert_global_to_local, cell_global_to_local; diff --git a/src/UnitTests/Meshes/EntityTagsTest.h b/src/UnitTests/Meshes/EntityTagsTest.h index 775cb1aeb192c07e1c069363aac0a9bb1b222336..f53755caf00670eadac755c8880f94b99e70ac48 100644 --- a/src/UnitTests/Meshes/EntityTagsTest.h +++ b/src/UnitTests/Meshes/EntityTagsTest.h @@ -48,8 +48,7 @@ TEST( MeshTest, RegularMeshOfQuadranglesTest ) typedef Mesh< TestQuadrangleMeshConfig > TestQuadrangleMesh; TestQuadrangleMesh mesh, mesh2; MeshBuilder< TestQuadrangleMesh > meshBuilder; - meshBuilder.setPointsCount( numberOfVertices ); - meshBuilder.setCellsCount( numberOfCells ); + meshBuilder.setEntitiesCount( numberOfVertices, numberOfCells ); /**** * Setup vertices diff --git a/src/UnitTests/Meshes/FPMAReaderTest.cpp b/src/UnitTests/Meshes/FPMAReaderTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bedfb05f7aa3d522c4873f876a8218da36b1ccc0 --- /dev/null +++ b/src/UnitTests/Meshes/FPMAReaderTest.cpp @@ -0,0 +1,51 @@ +#ifdef HAVE_GTEST +#include + +#include +#include +#include + +#include "data/loader.h" +#include "MeshReaderTest.h" + +using namespace TNL::Meshes; + +static const char* TEST_FILE_NAME = "test_FPMAReaderTest.fpma"; + +struct MyConfigTag {}; + +namespace TNL { +namespace Meshes { +namespace BuildConfigTags { + +// disable all grids +template< int Dimension, typename Real, typename Device, typename Index > +struct GridTag< MyConfigTag, Grid< Dimension, Real, Device, Index > >{ enum { enabled = false }; }; + +// enable meshes used in the tests +template<> struct MeshCellTopologyTag< MyConfigTag, Topologies::Polyhedron > { enum { enabled = true }; }; + +} // namespace BuildConfigTags +} // namespace Meshes +} // namespace TNL + +TEST( FPMAReaderTest, polyhedrons ) +{ + using MeshType = Mesh< DefaultConfig< Topologies::Polyhedron > >; + const MeshType mesh = loadMeshFromFile< MeshType, Readers::FPMAReader >( "polyhedrons/cube1m_1.fpma" ); + + // test that the mesh was actually loaded + const auto vertices = mesh.template getEntitiesCount< 0 >(); + const auto faces = mesh.template getEntitiesCount< MeshType::getMeshDimension() - 1 >(); + const auto cells = mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); + EXPECT_EQ( vertices, 2358 ); + EXPECT_EQ( faces, 2690 ); + EXPECT_EQ( cells, 395 ); + + test_reader< Readers::FPMAReader, Writers::FPMAWriter >( mesh, TEST_FILE_NAME ); + test_resolveAndLoadMesh< Writers::FPMAWriter, MyConfigTag >( mesh, TEST_FILE_NAME ); +} + +#endif + +#include "../main.h" diff --git a/src/UnitTests/Meshes/MeshGeometryTest.cpp b/src/UnitTests/Meshes/MeshGeometryTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c8d06ffde12b5905d6d83e0884d385f11bdefe7 --- /dev/null +++ b/src/UnitTests/Meshes/MeshGeometryTest.cpp @@ -0,0 +1,2 @@ +#include "MeshGeometryTest.h" +#include "../main.h" diff --git a/src/UnitTests/Meshes/MeshGeometryTest.cu b/src/UnitTests/Meshes/MeshGeometryTest.cu new file mode 100644 index 0000000000000000000000000000000000000000..1c8d06ffde12b5905d6d83e0884d385f11bdefe7 --- /dev/null +++ b/src/UnitTests/Meshes/MeshGeometryTest.cu @@ -0,0 +1,2 @@ +#include "MeshGeometryTest.h" +#include "../main.h" diff --git a/src/UnitTests/Meshes/MeshGeometryTest.h b/src/UnitTests/Meshes/MeshGeometryTest.h new file mode 100644 index 0000000000000000000000000000000000000000..146e04eaaf72015306acf786f29ccbe82f340d91 --- /dev/null +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -0,0 +1,1112 @@ +#pragma once + +#ifdef HAVE_GTEST +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace MeshGeometryTest { + +using namespace TNL; +using namespace TNL::Meshes; + +class TestPolygon2DMeshConfig : public DefaultConfig< Topologies::Polygon > +{ +public: + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) { return true; } + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } +}; + +class TestPolygon3DMeshConfig : public DefaultConfig< Topologies::Polygon > +{ +public: + static constexpr int spaceDimension = 3; + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) { return true; } + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } +}; + +class TestWedgeMeshConfig : public DefaultConfig< Topologies::Wedge > +{ +public: + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) { return true; } + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } +}; + +class TestPyramidMeshConfig : public DefaultConfig< Topologies::Pyramid > +{ +public: + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) { return true; } + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } +}; + +class TestPolyhedronMeshConfig : public DefaultConfig< Topologies::Polyhedron > +{ +public: + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) { return true; } + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } +}; + +TEST( MeshGeometryTest, Polygon2DAreaTest ) +{ + using PolygonTestMesh = Mesh< TestPolygon2DMeshConfig >; + using PolygonMeshEntityType = MeshEntity< TestPolygon2DMeshConfig, Devices::Host, Topologies::Polygon >; + using VertexMeshEntityType = typename PolygonMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + + // Set up a non-convex 2D polygon. + + PointType point0( 3.0, 4.0 ), + point1( 5.0, 11.0 ), + point2( 12.0, 8.0 ), + point3( 9.0, 5.0 ), + point4( 5.0, 6.0 ); + + PolygonTestMesh mesh; + MeshBuilder< PolygonTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 5, 1 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + + meshBuilder.setCellCornersCounts( { 5 } ); + + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + EXPECT_NEAR( getEntityMeasure( mesh, mesh.template getEntity< 2 >( 0 ) ), + 30.0, + 1e-6 ); +} + +TEST( MeshGeometryTest, Polygon3DAreaTest ) +{ + using PolygonTestMesh = Mesh< TestPolygon3DMeshConfig >; + using PolygonMeshEntityType = MeshEntity< TestPolygon3DMeshConfig, Devices::Host, Topologies::Polygon >; + using VertexMeshEntityType = typename PolygonMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + + // Set up a non-convex 3D polygon, that is not aligned to any of the axis. + + /* + PointType point0( 3.0, 4.0, 1.0 ), + point1( 5.0, 11.0, 1.0 ), + point2( 12.0, 8.0, 1.0 ), + point3( 9.0, 5.0, 1.0 ), + point4( 5.0, 6.0, 1.0 );*/ + + // Above points rotated: + PointType point0( 1.25245, 4.16176, 2.66667 ), + point1( 0.08280, 10.41230, 6.21105 ), + point2( 7.16272, 11.94879, 3.86289 ), + point3( 5.86983, 8.12036, 2.56999 ), + point4( 2.11438, 6.71405, 3.52860 ); + + PolygonTestMesh mesh; + MeshBuilder< PolygonTestMesh > meshBuilder; + meshBuilder.setEntitiesCount( 5, 1 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + + meshBuilder.setCellCornersCounts( { 5 } ); + + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + EXPECT_NEAR( getEntityMeasure( mesh, mesh.template getEntity< 2 >( 0 ) ), + 30.0, + 1e-4 ); +} + +TEST( MeshGeometryTest, WedgeAreaTest ) +{ + using WedgeTestMesh = Mesh< TestWedgeMeshConfig >; + using WedgeMeshEntityType = MeshEntity< TestWedgeMeshConfig, Devices::Host, Topologies::Wedge >; + using VertexMeshEntityType = typename WedgeMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + + PointType point0( 10.0, 10.0, 10.0 ), + point1( 14.0, 10.0, 10.0 ), + point2( 12.0, 10.0, 16.0 ), + point3( 10.0, 19.0, 10.0 ), + point4( 14.0, 19.0, 10.0 ), + point5( 12.0, 19.0, 16.0 ); + + WedgeTestMesh mesh; + MeshBuilder< WedgeTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 6, 1 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + meshBuilder.setPoint( 5, point5 ); + + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + EXPECT_NEAR( getEntityMeasure( mesh, mesh.template getEntity< 3 >( 0 ) ), + 108.0, + 1e-6 ); +} + +TEST( MeshGeometryTest, PyramidAreaTest ) +{ + using PyramidTestMesh = Mesh< TestPyramidMeshConfig >; + using PyramidMeshEntityType = MeshEntity< TestPyramidMeshConfig, Devices::Host, Topologies::Pyramid >; + using VertexMeshEntityType = typename PyramidMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + + // Set up a pyramid of height 10 with a square base of size 10. + + PointType point0( 10.0, 10.0, 10.0 ), + point1( 20.0, 10.0, 10.0 ), + point2( 20.0, 20.0, 10.0 ), + point3( 10.0, 20.0, 10.0 ), + point4( 15.0, 15.0, 20.0 ); + + PyramidTestMesh mesh; + MeshBuilder< PyramidTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 5, 1 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + EXPECT_NEAR( getEntityMeasure( mesh, mesh.template getEntity< 3 >( 0 ) ), + 1000.0 / 3.0, + 1e-6 ); +} + +TEST( MeshGeometryTest, PolyhedronAreaTest ) +{ + using PolyhedronTestMesh = Mesh< TestPolyhedronMeshConfig >; + using PolyhedronMeshEntityType = MeshEntity< TestPolyhedronMeshConfig, Devices::Host, Topologies::Polyhedron >; + using VertexMeshEntityType = typename PolyhedronMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + + // Set up a cube of size 10 with a pyramid of height 10 sitting on top. + + PointType point0( 10.0, 10.0, 10.0 ), + point1( 20.0, 10.0, 10.0 ), + point2( 10.0, 20.0, 10.0 ), + point3( 20.0, 20.0, 10.0 ), + point4( 10.0, 10.0, 20.0 ), + point5( 20.0, 10.0, 20.0 ), + point6( 10.0, 20.0, 20.0 ), + point7( 20.0, 20.0, 20.0 ), + point8( 15.0, 15.0, 30.0 ); + + PolyhedronTestMesh mesh; + MeshBuilder< PolyhedronTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 9, 1, 9 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + meshBuilder.setPoint( 5, point5 ); + meshBuilder.setPoint( 6, point6 ); + meshBuilder.setPoint( 7, point7 ); + meshBuilder.setPoint( 8, point8 ); + + meshBuilder.setFaceCornersCounts( { 4, 4, 4, 4, 4, 3, 3, 3, 3 } ); + + meshBuilder.getFaceSeed( 0 ).setCornerId( 0, 2 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 1, 3 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 2, 1 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 3, 0 ); + + meshBuilder.getFaceSeed( 1 ).setCornerId( 0, 1 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 1, 3 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 2, 7 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 3, 5 ); + + meshBuilder.getFaceSeed( 2 ).setCornerId( 0, 2 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 1, 0 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 2, 4 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 3, 6 ); + + meshBuilder.getFaceSeed( 3 ).setCornerId( 0, 0 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 2, 5 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 3, 4 ); + + meshBuilder.getFaceSeed( 4 ).setCornerId( 0, 3 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 1, 2 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 2, 6 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 3, 7 ); + + meshBuilder.getFaceSeed( 5 ).setCornerId( 0, 4 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 1, 5 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 2, 8 ); + + meshBuilder.getFaceSeed( 6 ).setCornerId( 0, 5 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 2, 8 ); + + meshBuilder.getFaceSeed( 7 ).setCornerId( 0, 7 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 1, 6 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 2, 8 ); + + meshBuilder.getFaceSeed( 8 ).setCornerId( 0, 6 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 1, 4 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 8 ); + + meshBuilder.setCellCornersCounts( { 9 } ); + + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 6, 6 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 7, 7 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 8, 8 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + EXPECT_NEAR( getEntityMeasure( mesh, mesh.template getEntity< 3 >( 0 ) ), + 1000.0 + ( 1000.0 / 3.0 ), + 1e-6 ); +} + +TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) +{ + using PolygonTestMesh = Mesh< TestPolygon3DMeshConfig >; + using PolygonMeshEntityType = MeshEntity< TestPolygon3DMeshConfig, Devices::Host, Topologies::Polygon >; + using VertexMeshEntityType = typename PolygonMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + using RealType = typename PolygonTestMesh::RealType; + + const PointType offset( 0.100, 0.125, 0.150 ); + + // Set up 1 planar and 5 non-planar non-convex 3D polygons. + + /* + PointType point0( 3.0, 4.0, 1.0 ), + point1( 5.0, 11.0, 1.0 ), + point2( 12.0, 8.0, 1.0 ), + point3( 9.0, 5.0, 1.0 ), + point4( 5.0, 6.0, 1.0 );*/ + + // Above points rotated: + PointType point0( 1.25245, 4.16176, 2.66667 ), + point1( 0.08280, 10.41230, 6.21105 ), + point2( 7.16272, 11.94879, 3.86289 ), + point3( 5.86983, 8.12036, 2.56999 ), + point4( 2.11438, 6.71405, 3.52860 ); + + // Previous 5 points deviated by offset: + PointType point0_( point0 + offset ), + point1_( point1 + offset ), + point2_( point2 + offset ), + point3_( point3 + offset ), + point4_( point4 + offset ); + + PolygonTestMesh mesh; + MeshBuilder< PolygonTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 10, 6 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + meshBuilder.setPoint( 5, point0_ ); + meshBuilder.setPoint( 6, point1_ ); + meshBuilder.setPoint( 7, point2_ ); + meshBuilder.setPoint( 8, point3_ ); + meshBuilder.setPoint( 9, point4_ ); + + meshBuilder.setCellCornersCounts( { 5, 5, 5, 5, 5, 5 } ); + + // Planar cell with non-deviated points + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + + // Non-Planar cell with 0th point deviated + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 5 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 4, 4 ); + + // Non-Planar cell with 1th point deviated + meshBuilder.getCellSeed( 2 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 2 ).setCornerId( 1, 6 ); + meshBuilder.getCellSeed( 2 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 2 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 2 ).setCornerId( 4, 4 ); + + // Non-Planar cell with 2th point deviated + meshBuilder.getCellSeed( 3 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 3 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 3 ).setCornerId( 2, 7 ); + meshBuilder.getCellSeed( 3 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 3 ).setCornerId( 4, 4 ); + + // Non-Planar cell with 3th point deviated + meshBuilder.getCellSeed( 4 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 3, 8 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 4, 4 ); + + // Non-Planar cell with 4th point deviated + meshBuilder.getCellSeed( 5 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 4, 9 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + EXPECT_EQ( isPlanar( mesh, mesh.template getEntity< 2 >( 0 ), 1e-4 ), true ); + EXPECT_EQ( isPlanar( mesh, mesh.template getEntity< 2 >( 1 ), 1e-4 ), false ); + EXPECT_EQ( isPlanar( mesh, mesh.template getEntity< 2 >( 2 ), 1e-4 ), false ); + EXPECT_EQ( isPlanar( mesh, mesh.template getEntity< 2 >( 3 ), 1e-4 ), false ); + EXPECT_EQ( isPlanar( mesh, mesh.template getEntity< 2 >( 4 ), 1e-4 ), false ); + EXPECT_EQ( isPlanar( mesh, mesh.template getEntity< 2 >( 5 ), 1e-4 ), false ); +} + +TEST( MeshGeometryTest, PolygonDecompositionTest ) +{ + using PolygonTestMesh = Mesh< TestPolygon2DMeshConfig >; + using PolygonMeshEntityType = MeshEntity< TestPolygon2DMeshConfig, Devices::Host, Topologies::Polygon >; + using VertexMeshEntityType = typename PolygonMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + + PolygonTestMesh mesh; + MeshBuilder< PolygonTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 16, 7 ); + + meshBuilder.setPoint( 0, PointType( 0.250, 0.150 ) ); + meshBuilder.setPoint( 1, PointType( 0.150, 0.250 ) ); + meshBuilder.setPoint( 2, PointType( 0.900, 0.500 ) ); + meshBuilder.setPoint( 3, PointType( 0.750, 0.275 ) ); + meshBuilder.setPoint( 4, PointType( 0.500, 0.900 ) ); + meshBuilder.setPoint( 5, PointType( 0.275, 0.750 ) ); + meshBuilder.setPoint( 6, PointType( 0.000, 0.250 ) ); + meshBuilder.setPoint( 7, PointType( 0.250, 0.000 ) ); + meshBuilder.setPoint( 8, PointType( 0.000, 0.000 ) ); + meshBuilder.setPoint( 9, PointType( 0.750, 0.000 ) ); + meshBuilder.setPoint( 10, PointType( 0.000, 0.750 ) ); + meshBuilder.setPoint( 11, PointType( 1.000, 0.500 ) ); + meshBuilder.setPoint( 12, PointType( 1.000, 0.000 ) ); + meshBuilder.setPoint( 13, PointType( 0.500, 1.000 ) ); + meshBuilder.setPoint( 14, PointType( 1.000, 1.000 ) ); + meshBuilder.setPoint( 15, PointType( 0.000, 1.000 ) ); + + /**** + * Setup the following polygons: + * + * 1 0 3 2 4 5 + * 8 7 0 1 6 + * 9 3 0 7 + * 6 1 5 10 + * 12 11 2 3 9 + * 13 4 2 11 14 + * 10 5 4 13 15 + */ + + meshBuilder.setCellCornersCounts( { 6, 5, 4, 4, 5, 5, 5 } ); + + // 1 0 3 2 4 5 + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); + + // 8 7 0 1 6 + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 8 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 7 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 0 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 3, 1 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 4, 6 ); + + // 9 3 0 7 + meshBuilder.getCellSeed( 2 ).setCornerId( 0, 9 ); + meshBuilder.getCellSeed( 2 ).setCornerId( 1, 3 ); + meshBuilder.getCellSeed( 2 ).setCornerId( 2, 0 ); + meshBuilder.getCellSeed( 2 ).setCornerId( 3, 7 ); + + // 6 1 5 10 + meshBuilder.getCellSeed( 3 ).setCornerId( 0, 6 ); + meshBuilder.getCellSeed( 3 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 3 ).setCornerId( 2, 5 ); + meshBuilder.getCellSeed( 3 ).setCornerId( 3, 10 ); + + // 12 11 2 3 9 + meshBuilder.getCellSeed( 4 ).setCornerId( 0, 12 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 1, 11 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 4, 9 ); + + // 13 4 2 11 14 + meshBuilder.getCellSeed( 5 ).setCornerId( 0, 13 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 1, 4 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 3, 11 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 4, 14 ); + + // 10 5 4 13 15 + meshBuilder.getCellSeed( 6 ).setCornerId( 0, 10 ); + meshBuilder.getCellSeed( 6 ).setCornerId( 1, 5 ); + meshBuilder.getCellSeed( 6 ).setCornerId( 2, 4 ); + meshBuilder.getCellSeed( 6 ).setCornerId( 3, 13 ); + meshBuilder.getCellSeed( 6 ).setCornerId( 4, 15 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + // Test for the 1st version + { + const auto triangleMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + EXPECT_EQ( triangleMesh.getEntitiesCount< 0 >(), 23 ); + EXPECT_EQ( triangleMesh.getEntitiesCount< 2 >(), 34 ); + } + + // Test for the 2nd version + { + const auto triangleMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + EXPECT_EQ( triangleMesh.getEntitiesCount< 0 >(), 16 ); + EXPECT_EQ( triangleMesh.getEntitiesCount< 2 >(), 20 ); + } +} + +TEST( MeshGeometryTest, PolyhedronDecompositionTest ) +{ + using PolyhedronTestMesh = Mesh< TestPolyhedronMeshConfig >; + using PolyhedronMeshEntityType = MeshEntity< TestPolyhedronMeshConfig, Devices::Host, Topologies::Polyhedron >; + using VertexMeshEntityType = typename PolyhedronMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + + PointType point0 ( -1.25000, 1.16650, 1.20300 ), + point1 ( -1.20683, 1.16951, 1.20537 ), + point2 ( -1.16843, 1.19337, 1.17878 ), + point3 ( -1.21025, 1.21901, 1.15383 ), + point4 ( -1.25000, 1.21280, 1.15670 ), + point5 ( -1.20816, 1.25000, 1.16756 ), + point6 ( -1.25000, 1.25000, 1.18056 ), + point7 ( -1.14802, 1.21553, 1.21165 ), + point8 ( -1.16186, 1.25000, 1.21385 ), + point9 ( -1.20307, 1.17486, 1.25000 ), + point10( -1.25000, 1.18056, 1.25000 ), + point11( -1.15677, 1.22115, 1.25000 ), + point12( -1.18056, 1.25000, 1.25000 ), + point13( -1.25000, 1.25000, 1.25000 ), + point14( -1.09277, 1.20806, 1.19263 ), + point15( -1.07219, 1.22167, 1.17994 ), + point16( -1.07215, 1.25000, 1.18679 ), + point17( -1.05697, 1.21124, 1.19697 ), + point18( -1.04607, 1.21508, 1.22076 ), + point19( -1.02140, 1.25000, 1.22293 ), + point20( -1.06418, 1.22115, 1.25000 ), + point21( -1.04167, 1.25000, 1.25000 ); + + PolyhedronTestMesh mesh; + MeshBuilder< PolyhedronTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 22, 2, 16 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + meshBuilder.setPoint( 5, point5 ); + meshBuilder.setPoint( 6, point6 ); + meshBuilder.setPoint( 7, point7 ); + meshBuilder.setPoint( 8, point8 ); + meshBuilder.setPoint( 9, point9 ); + meshBuilder.setPoint( 10, point10 ); + meshBuilder.setPoint( 11, point11 ); + meshBuilder.setPoint( 12, point12 ); + meshBuilder.setPoint( 13, point13 ); + meshBuilder.setPoint( 14, point14 ); + meshBuilder.setPoint( 15, point15 ); + meshBuilder.setPoint( 16, point16 ); + meshBuilder.setPoint( 17, point17 ); + meshBuilder.setPoint( 18, point18 ); + meshBuilder.setPoint( 19, point19 ); + meshBuilder.setPoint( 20, point20 ); + meshBuilder.setPoint( 21, point21 ); + + /**** + * Setup the following faces (polygons): + * + * 0 1 2 3 4 + * 4 3 5 6 + * 5 3 2 7 8 + * 9 1 0 10 + * 11 7 2 1 9 + * 8 7 11 12 + * 13 12 11 9 10 + * 13 10 0 4 6 + * 13 6 5 8 12 + * 8 7 14 15 16 + * 16 15 17 18 19 + * 20 18 17 14 7 11 + * 17 15 14 + * 21 19 18 20 + * 21 20 11 12 + * 12 8 16 19 21 + * + * NOTE: indices refer to the points + */ + + meshBuilder.setFaceCornersCounts( { 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 6, 3, 4, 4, 5 } ); + + // 0 1 2 3 4 + meshBuilder.getFaceSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 4, 4 ); + + // 4 3 5 6 + meshBuilder.getFaceSeed( 1 ).setCornerId( 0, 4 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 1, 3 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 2, 5 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 3, 6 ); + + // 5 3 2 7 8 + meshBuilder.getFaceSeed( 2 ).setCornerId( 0, 5 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 1, 3 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 3, 7 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 4, 8 ); + + // 9 1 0 10 + meshBuilder.getFaceSeed( 3 ).setCornerId( 0, 9 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 2, 0 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 3, 10 ); + + // 11 7 2 1 9 + meshBuilder.getFaceSeed( 4 ).setCornerId( 0, 11 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 3, 1 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 4, 9 ); + + // 8 7 11 12 + meshBuilder.getFaceSeed( 5 ).setCornerId( 0, 8 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 2, 11 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 3, 12 ); + + // 13 12 11 9 10 + meshBuilder.getFaceSeed( 6 ).setCornerId( 0, 13 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 1, 12 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 2, 11 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 3, 9 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 4, 10 ); + + // 13 10 0 4 6 + meshBuilder.getFaceSeed( 7 ).setCornerId( 0, 13 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 1, 10 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 2, 0 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 3, 4 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 4, 6 ); + + // 13 6 5 8 12 + meshBuilder.getFaceSeed( 8 ).setCornerId( 0, 13 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 1, 6 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 5 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 3, 8 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 4, 12 ); + + // 8 7 14 15 16 + meshBuilder.getFaceSeed( 9 ).setCornerId( 0, 8 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 2, 14 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 3, 15 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 4, 16 ); + + // 16 15 17 18 19 + meshBuilder.getFaceSeed( 10 ).setCornerId( 0, 16 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 1, 15 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 2, 17 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 3, 18 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 4, 19 ); + + // 20 18 17 14 7 11 + meshBuilder.getFaceSeed( 11 ).setCornerId( 0, 20 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 1, 18 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 2, 17 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 3, 14 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 4, 7 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 5, 11 ); + + // 17 15 14 + meshBuilder.getFaceSeed( 12 ).setCornerId( 0, 17 ); + meshBuilder.getFaceSeed( 12 ).setCornerId( 1, 15 ); + meshBuilder.getFaceSeed( 12 ).setCornerId( 2, 14 ); + + // 21 19 18 20 + meshBuilder.getFaceSeed( 13 ).setCornerId( 0, 21 ); + meshBuilder.getFaceSeed( 13 ).setCornerId( 1, 19 ); + meshBuilder.getFaceSeed( 13 ).setCornerId( 2, 18 ); + meshBuilder.getFaceSeed( 13 ).setCornerId( 3, 20 ); + + // 21 20 11 12 + meshBuilder.getFaceSeed( 14 ).setCornerId( 0, 21 ); + meshBuilder.getFaceSeed( 14 ).setCornerId( 1, 20 ); + meshBuilder.getFaceSeed( 14 ).setCornerId( 2, 11 ); + meshBuilder.getFaceSeed( 14 ).setCornerId( 3, 12 ); + + // 12 8 16 19 21 + meshBuilder.getFaceSeed( 15 ).setCornerId( 0, 12 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 1, 8 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 2, 16 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 3, 19 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 4, 21 ); + + /**** + * Setup the following cells (polyhedrons): + * + * 0 1 2 3 4 5 6 7 8 + * 9 10 11 12 13 5 14 15 + * + * NOTE: indices refer to the faces + */ + + meshBuilder.setCellCornersCounts( { 9, 8 } ); + + // 0 1 2 3 4 5 6 7 8 + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 6, 6 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 7, 7 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 8, 8 ); + + // 9 10 11 12 13 5 14 15 + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 9 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 10 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 11 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 3, 12 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 4, 13 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 5, 5 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 6, 14 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 7, 15 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + // Test for the 1st version + { + const auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 0 >(), 40 ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 3 >(), 76 ); + } + + // Test for the 2nd version + { + const auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 0 >(), 24 ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 3 >(), 44 ); + } + + // Test for the 3rd version + { + const auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 0 >(), 32 ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 3 >(), 48 ); + } + + // Test for the 4th version + { + const auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 0 >(), 22 ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 3 >(), 28 ); + } +} + +TEST( MeshGeometryTest, Polygon3DGetPlanarMeshTest ) +{ + using PolygonTestMesh = Mesh< TestPolygon3DMeshConfig >; + using PolygonMeshEntityType = MeshEntity< TestPolygon3DMeshConfig, Devices::Host, Topologies::Polygon >; + using VertexMeshEntityType = typename PolygonMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + using RealType = typename PolygonTestMesh::RealType; + + const PointType offset( 0.100, 0.125, 0.150 ); + + // Set up 1 planar and 1 non-planar polygons (quads) + + PointType point0( 0.0, 0.0, 0.0 ), + point1( 1.0, 0.0, 0.0 ), + point2( 1.0, 1.0, 0.0 ), + point3( 0.0, 1.0, 0.0 ), + point4( 2.0, 0.0, 0.0 ), + point5( 2.0, 1.0, 0.0 ); + + // 5th point deviated by offset: + point5 += offset; + + PolygonTestMesh mesh; + MeshBuilder< PolygonTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 6, 2 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + meshBuilder.setPoint( 5, point5 ); + + meshBuilder.setCellCornersCounts( { 4, 4 } ); + + // Planar cell + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 1 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 4 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 5 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 3, 2 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + // Write original mesh + { + using VTKWriter = Meshes::Writers::VTKWriter< decltype( mesh ) >; + std::ofstream file( "polygon_planarTest_orig.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( mesh ); + } + + // Test for the 1st version + { + const auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + EXPECT_EQ( planarMesh.getEntitiesCount< 0 >(), 7 ); + EXPECT_EQ( planarMesh.getEntitiesCount< 2 >(), 5 ); + } + + // Test for the 2nd version + { + const auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + EXPECT_EQ( planarMesh.getEntitiesCount< 0 >(), 6 ); + EXPECT_EQ( planarMesh.getEntitiesCount< 2 >(), 3 ); + } +} + +TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) +{ + using PolyhedronTestMesh = Mesh< TestPolyhedronMeshConfig >; + using PolyhedronMeshEntityType = MeshEntity< TestPolyhedronMeshConfig, Devices::Host, Topologies::Polyhedron >; + using VertexMeshEntityType = typename PolyhedronMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + + PointType point0 ( -1.25000, 1.16650, 1.20300 ), + point1 ( -1.20683, 1.16951, 1.20537 ), + point2 ( -1.16843, 1.19337, 1.17878 ), + point3 ( -1.21025, 1.21901, 1.15383 ), + point4 ( -1.25000, 1.21280, 1.15670 ), + point5 ( -1.20816, 1.25000, 1.16756 ), + point6 ( -1.25000, 1.25000, 1.18056 ), + point7 ( -1.14802, 1.21553, 1.21165 ), + point8 ( -1.16186, 1.25000, 1.21385 ), + point9 ( -1.20307, 1.17486, 1.25000 ), + point10( -1.25000, 1.18056, 1.25000 ), + point11( -1.15677, 1.22115, 1.25000 ), + point12( -1.18056, 1.25000, 1.25000 ), + point13( -1.25000, 1.25000, 1.25000 ), + point14( -1.09277, 1.20806, 1.19263 ), + point15( -1.07219, 1.22167, 1.17994 ), + point16( -1.07215, 1.25000, 1.18679 ), + point17( -1.05697, 1.21124, 1.19697 ), + point18( -1.04607, 1.21508, 1.22076 ), + point19( -1.02140, 1.25000, 1.22293 ), + point20( -1.06418, 1.22115, 1.25000 ), + point21( -1.04167, 1.25000, 1.25000 ); + + PolyhedronTestMesh mesh; + MeshBuilder< PolyhedronTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 22, 2, 16 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + meshBuilder.setPoint( 5, point5 ); + meshBuilder.setPoint( 6, point6 ); + meshBuilder.setPoint( 7, point7 ); + meshBuilder.setPoint( 8, point8 ); + meshBuilder.setPoint( 9, point9 ); + meshBuilder.setPoint( 10, point10 ); + meshBuilder.setPoint( 11, point11 ); + meshBuilder.setPoint( 12, point12 ); + meshBuilder.setPoint( 13, point13 ); + meshBuilder.setPoint( 14, point14 ); + meshBuilder.setPoint( 15, point15 ); + meshBuilder.setPoint( 16, point16 ); + meshBuilder.setPoint( 17, point17 ); + meshBuilder.setPoint( 18, point18 ); + meshBuilder.setPoint( 19, point19 ); + meshBuilder.setPoint( 20, point20 ); + meshBuilder.setPoint( 21, point21 ); + + /**** + * Setup the following faces (polygons): + * + * 0 1 2 3 4 + * 4 3 5 6 + * 5 3 2 7 8 + * 9 1 0 10 + * 11 7 2 1 9 + * 8 7 11 12 + * 13 12 11 9 10 + * 13 10 0 4 6 + * 13 6 5 8 12 + * 8 7 14 15 16 + * 16 15 17 18 19 + * 20 18 17 14 7 11 + * 17 15 14 + * 21 19 18 20 + * 21 20 11 12 + * 12 8 16 19 21 + * + * NOTE: indices refer to the points + */ + + meshBuilder.setFaceCornersCounts( { 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 6, 3, 4, 4, 5 } ); + + // 0 1 2 3 4 + meshBuilder.getFaceSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 4, 4 ); + + // 4 3 5 6 + meshBuilder.getFaceSeed( 1 ).setCornerId( 0, 4 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 1, 3 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 2, 5 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 3, 6 ); + + // 5 3 2 7 8 + meshBuilder.getFaceSeed( 2 ).setCornerId( 0, 5 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 1, 3 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 3, 7 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 4, 8 ); + + // 9 1 0 10 + meshBuilder.getFaceSeed( 3 ).setCornerId( 0, 9 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 2, 0 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 3, 10 ); + + // 11 7 2 1 9 + meshBuilder.getFaceSeed( 4 ).setCornerId( 0, 11 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 3, 1 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 4, 9 ); + + // 8 7 11 12 + meshBuilder.getFaceSeed( 5 ).setCornerId( 0, 8 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 2, 11 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 3, 12 ); + + // 13 12 11 9 10 + meshBuilder.getFaceSeed( 6 ).setCornerId( 0, 13 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 1, 12 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 2, 11 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 3, 9 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 4, 10 ); + + // 13 10 0 4 6 + meshBuilder.getFaceSeed( 7 ).setCornerId( 0, 13 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 1, 10 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 2, 0 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 3, 4 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 4, 6 ); + + // 13 6 5 8 12 + meshBuilder.getFaceSeed( 8 ).setCornerId( 0, 13 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 1, 6 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 5 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 3, 8 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 4, 12 ); + + // 8 7 14 15 16 + meshBuilder.getFaceSeed( 9 ).setCornerId( 0, 8 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 2, 14 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 3, 15 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 4, 16 ); + + // 16 15 17 18 19 + meshBuilder.getFaceSeed( 10 ).setCornerId( 0, 16 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 1, 15 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 2, 17 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 3, 18 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 4, 19 ); + + // 20 18 17 14 7 11 + meshBuilder.getFaceSeed( 11 ).setCornerId( 0, 20 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 1, 18 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 2, 17 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 3, 14 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 4, 7 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 5, 11 ); + + // 17 15 14 + meshBuilder.getFaceSeed( 12 ).setCornerId( 0, 17 ); + meshBuilder.getFaceSeed( 12 ).setCornerId( 1, 15 ); + meshBuilder.getFaceSeed( 12 ).setCornerId( 2, 14 ); + + // 21 19 18 20 + meshBuilder.getFaceSeed( 13 ).setCornerId( 0, 21 ); + meshBuilder.getFaceSeed( 13 ).setCornerId( 1, 19 ); + meshBuilder.getFaceSeed( 13 ).setCornerId( 2, 18 ); + meshBuilder.getFaceSeed( 13 ).setCornerId( 3, 20 ); + + // 21 20 11 12 + meshBuilder.getFaceSeed( 14 ).setCornerId( 0, 21 ); + meshBuilder.getFaceSeed( 14 ).setCornerId( 1, 20 ); + meshBuilder.getFaceSeed( 14 ).setCornerId( 2, 11 ); + meshBuilder.getFaceSeed( 14 ).setCornerId( 3, 12 ); + + // 12 8 16 19 21 + meshBuilder.getFaceSeed( 15 ).setCornerId( 0, 12 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 1, 8 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 2, 16 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 3, 19 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 4, 21 ); + + /**** + * Setup the following cells (polyhedrons): + * + * 0 1 2 3 4 5 6 7 8 + * 9 10 11 12 13 5 14 15 + * + * NOTE: indices refer to the faces + */ + + meshBuilder.setCellCornersCounts( { 9, 8 } ); + + // 0 1 2 3 4 5 6 7 8 + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 6, 6 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 7, 7 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 8, 8 ); + + // 9 10 11 12 13 5 14 15 + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 9 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 10 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 11 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 3, 12 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 4, 13 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 5, 5 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 6, 14 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 7, 15 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + // Test for the 1st version + { + const auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + EXPECT_EQ( planarMesh.getEntitiesCount< 0 >(), 31 ); + EXPECT_EQ( planarMesh.getEntitiesCount< 2 >(), 50 ); + EXPECT_EQ( planarMesh.getEntitiesCount< 3 >(), 2 ); + } + + // Test for the 2nd version + { + const auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + EXPECT_EQ( planarMesh.getEntitiesCount< 0 >(), 22 ); + EXPECT_EQ( planarMesh.getEntitiesCount< 2 >(), 32 ); + EXPECT_EQ( planarMesh.getEntitiesCount< 3 >(), 2 ); + } +} + +} // namespace MeshTest + +#endif diff --git a/src/UnitTests/Meshes/MeshOrderingTest.h b/src/UnitTests/Meshes/MeshOrderingTest.h index 998e8b245afc501fc124c0d0d3f0137ab4886b4e..b06f9a9e1482121c7dd6c3c74fae9ab4dba52d7f 100644 --- a/src/UnitTests/Meshes/MeshOrderingTest.h +++ b/src/UnitTests/Meshes/MeshOrderingTest.h @@ -67,13 +67,14 @@ bool buildTriangleMesh( Mesh< TestTriangleMeshConfig, Device >& mesh ) point3( 1.0, 1.0 ); MeshBuilder< TriangleMesh > meshBuilder; - meshBuilder.setPointsCount( 4 ); + + meshBuilder.setEntitiesCount( 4, 2 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); meshBuilder.setPoint( 3, point3 ); - meshBuilder.setCellsCount( 2 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); diff --git a/src/UnitTests/Meshes/MeshTest.h b/src/UnitTests/Meshes/MeshTest.h index 9125e04e83b1404bd5e3e6e3f5c47e0b1ea1d0f6..b50e1f0232dba890bfb9515062d660a8b4ed968f 100644 --- a/src/UnitTests/Meshes/MeshTest.h +++ b/src/UnitTests/Meshes/MeshTest.h @@ -14,6 +14,10 @@ #include #include #include +#include +#include +#include +#include #include #include "EntityTests.h" @@ -55,6 +59,41 @@ public: static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } }; +class TestTwoPolygonsMeshConfig : public DefaultConfig< Topologies::Polygon > +{ +public: + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) { return true; } + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } +}; + +class TestSevenPolygonsMeshConfig : public DefaultConfig< Topologies::Polygon > +{ +public: + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) { return true; } + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } +}; + +class TestTwoWedgesMeshConfig : public DefaultConfig< Topologies::Wedge > +{ +public: + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) { return true; } + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } +}; + +class TestTwoPyramidsMeshConfig : public DefaultConfig< Topologies::Pyramid > +{ +public: + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) { return true; } + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } +}; + +class TestTwoPolyhedronsMeshConfig : public DefaultConfig< Topologies::Polyhedron > +{ +public: + static constexpr bool subentityStorage( int entityDimension, int subentityDimension ) { return true; } + static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } +}; + template< typename Object1, typename Object2 > void compareStringRepresentation( const Object1& obj1, const Object2& obj2 ) { @@ -157,13 +196,14 @@ TEST( MeshTest, TwoTrianglesTest ) typedef Mesh< TestTriangleMeshConfig > TriangleTestMesh; TriangleTestMesh mesh; MeshBuilder< TriangleTestMesh > meshBuilder; - meshBuilder.setPointsCount( 4 ); + + meshBuilder.setEntitiesCount( 4, 2 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); meshBuilder.setPoint( 3, point3 ); - meshBuilder.setCellsCount( 2 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -246,7 +286,9 @@ TEST( MeshTest, TetrahedronsTest ) typedef Mesh< TestTetrahedronMeshConfig > TestTetrahedronMesh; TestTetrahedronMesh mesh; MeshBuilder< TestTetrahedronMesh > meshBuilder; - meshBuilder.setPointsCount( 13 ); + + meshBuilder.setEntitiesCount( 13, 18 ); + meshBuilder.setPoint( 0, PointType( 0.000000, 0.000000, 0.000000 ) ); meshBuilder.setPoint( 1, PointType( 0.000000, 0.000000, 8.000000 ) ); meshBuilder.setPoint( 2, PointType( 0.000000, 8.000000, 0.000000 ) ); @@ -285,7 +327,6 @@ TEST( MeshTest, TetrahedronsTest ) * 12 3 6 10 */ - meshBuilder.setCellsCount( 18 ); // 12 8 7 5 meshBuilder.getCellSeed( 0 ).setCornerId( 0, 12 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 8 ); @@ -419,8 +460,7 @@ TEST( MeshTest, RegularMeshOfTrianglesTest ) typedef Mesh< TestTriangleMeshConfig > TestTriangleMesh; Mesh< TestTriangleMeshConfig > mesh; MeshBuilder< TestTriangleMesh > meshBuilder; - meshBuilder.setPointsCount( numberOfVertices ); - meshBuilder.setCellsCount( numberOfCells ); + meshBuilder.setEntitiesCount( numberOfVertices, numberOfCells ); /**** * Setup vertices @@ -520,8 +560,7 @@ TEST( MeshTest, RegularMeshOfQuadranglesTest ) typedef Mesh< TestQuadrangleMeshConfig > TestQuadrangleMesh; TestQuadrangleMesh mesh; MeshBuilder< TestQuadrangleMesh > meshBuilder; - meshBuilder.setPointsCount( numberOfVertices ); - meshBuilder.setCellsCount( numberOfCells ); + meshBuilder.setEntitiesCount( numberOfVertices, numberOfCells ); /**** * Setup vertices @@ -654,8 +693,7 @@ TEST( MeshTest, RegularMeshOfHexahedronsTest ) typedef Mesh< TestHexahedronMeshConfig > TestHexahedronMesh; TestHexahedronMesh mesh; MeshBuilder< TestHexahedronMesh > meshBuilder; - meshBuilder.setPointsCount( numberOfVertices ); - meshBuilder.setCellsCount( numberOfCells ); + meshBuilder.setEntitiesCount( numberOfVertices, numberOfCells ); /**** * Setup vertices @@ -968,6 +1006,2680 @@ TEST( MeshTest, RegularMeshOfHexahedronsTest ) testFinishedMesh( mesh ); } +TEST( MeshTest, TwoPolygonsTest ) +{ + using PolygonTestMesh = Mesh< TestTwoPolygonsMeshConfig >; + using PolygonMeshEntityType = MeshEntity< TestTwoPolygonsMeshConfig, Devices::Host, Topologies::Polygon >; + using EdgeMeshEntityType = typename PolygonMeshEntityType::SubentityTraits< 1 >::SubentityType; + using VertexMeshEntityType = typename PolygonMeshEntityType::SubentityTraits< 0 >::SubentityType; + + static_assert( PolygonMeshEntityType::SubentityTraits< 1 >::storageEnabled, "Testing polygon entity does not store edges as required." ); + static_assert( PolygonMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing polygon entity does not store vertices as required." ); + static_assert( EdgeMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing edge entity does not store vertices as required." ); + static_assert( EdgeMeshEntityType::SuperentityTraits< 2 >::storageEnabled, "Testing edge entity does not store polygons as required." ); + static_assert( VertexMeshEntityType::SuperentityTraits< 2 >::storageEnabled, "Testing vertex entity does not store polygons as required." ); + static_assert( VertexMeshEntityType::SuperentityTraits< 1 >::storageEnabled, "Testing vertex entity does not store edges as required." ); + + using PointType = typename VertexMeshEntityType::PointType; + static_assert( std::is_same< PointType, Containers::StaticVector< 2, RealType > >::value, + "unexpected PointType" ); + /**** + * We set-up the following situation + + point4 + /\ + / \ + / \ + / \ + edge5 edge4 + / \ + / polygon1 \ + / (triangle) \ + / \ + / \ + point3 /________edge2_______\ point2 + | | + | | + | polygon0 | + | (quad) | + edge3 edge1 + | | + |____________________| + point0 edge0 point1 + + */ + + PointType point0( 0.0, 0.0 ), + point1( 1.0, 0.0 ), + point2( 0.0, 0.5 ), + point3( 1.0, 0.5 ), + point4( 0.5, 1.0 ); + + PolygonTestMesh mesh; + MeshBuilder< PolygonTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 5, 2 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + + meshBuilder.setCellCornersCounts( { 4, 3 } ); + + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 3 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 2 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 4 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + // tests for entities counts + EXPECT_EQ( mesh.getEntitiesCount< 2 >(), 2 ); + EXPECT_EQ( mesh.getEntitiesCount< 1 >(), 6 ); + EXPECT_EQ( mesh.getEntitiesCount< 0 >(), 5 ); + + // tests for points + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).getPoint(), point0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).getPoint(), point1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).getPoint(), point2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).getPoint(), point3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).getPoint(), point4 ); + + // tests for the subentities layer + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSubentityIndex< 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSubentityIndex< 0 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSubentityIndex< 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSubentityIndex< 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSubentityIndex< 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSubentityIndex< 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSubentityIndex< 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSubentityIndex< 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSubentityIndex< 0 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSubentityIndex< 0 >( 1 ), 3 ); + + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentitiesCount< 0 >(), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 0 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentitiesCount< 1 >(), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 1 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 1 >( 3 ), 3 ); + + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentitiesCount< 0 >(), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 0 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 0 >( 2 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentitiesCount< 0 >(), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 1 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 1 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 1 >( 2 ), 5 ); + + // tests for the superentities layer + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 1 >(), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex< 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex< 1 >( 1 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 2 >(), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex< 2 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 1 >(), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex< 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex< 1 >( 1 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 2 >(), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex< 2 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 1 >(), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex< 1 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex< 1 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex< 1 >( 2 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 2 >(), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex< 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex< 2 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 1 >(), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex< 1 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex< 1 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex< 1 >( 2 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 2 >(), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex< 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex< 2 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 1 >(), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex< 1 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex< 1 >( 1 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 2 >(), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex< 2 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentitiesCount< 2 >(), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex< 2 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentitiesCount< 2 >(), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex< 2 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentitiesCount< 2 >(), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex< 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex< 2 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentitiesCount< 2 >(), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex< 2 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentitiesCount< 2 >(), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex< 2 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentitiesCount< 2 >(), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex< 2 >( 0 ), 1 ); + + // tests for the dual graph layer + ASSERT_EQ( mesh.getCellNeighborsCount( 0 ), 1 ); + EXPECT_EQ( mesh.getCellNeighborIndex( 0, 0 ), 1 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 1 ), 1 ); + EXPECT_EQ( mesh.getCellNeighborIndex( 1, 0 ), 0 ); + + testFinishedMesh( mesh ); +}; + +TEST( MeshTest, SevenPolygonsTest ) +{ + using PolygonTestMesh = Mesh< TestSevenPolygonsMeshConfig >; + using PolygonMeshEntityType = MeshEntity< TestSevenPolygonsMeshConfig, Devices::Host, Topologies::Polygon >; + using EdgeMeshEntityType = typename PolygonMeshEntityType::SubentityTraits< 1 >::SubentityType; + using VertexMeshEntityType = typename PolygonMeshEntityType::SubentityTraits< 0 >::SubentityType; + + static_assert( PolygonMeshEntityType::SubentityTraits< 1 >::storageEnabled, "Testing polygon entity does not store edges as required." ); + static_assert( PolygonMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing polygon entity does not store vertices as required." ); + static_assert( EdgeMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing edge entity does not store vertices as required." ); + static_assert( EdgeMeshEntityType::SuperentityTraits< 2 >::storageEnabled, "Testing edge entity does not store polygons as required." ); + static_assert( VertexMeshEntityType::SuperentityTraits< 2 >::storageEnabled, "Testing vertex entity does not store polygons as required." ); + static_assert( VertexMeshEntityType::SuperentityTraits< 1 >::storageEnabled, "Testing vertex entity does not store edges as required." ); + + using PointType = typename VertexMeshEntityType::PointType; + static_assert( std::is_same< PointType, Containers::StaticVector< 2, RealType > >::value, + "unexpected PointType" ); + + PolygonTestMesh mesh; + MeshBuilder< PolygonTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 16, 7 ); + + meshBuilder.setPoint( 0, PointType( 0.250, 0.150 ) ); + meshBuilder.setPoint( 1, PointType( 0.150, 0.250 ) ); + meshBuilder.setPoint( 2, PointType( 0.900, 0.500 ) ); + meshBuilder.setPoint( 3, PointType( 0.750, 0.275 ) ); + meshBuilder.setPoint( 4, PointType( 0.500, 0.900 ) ); + meshBuilder.setPoint( 5, PointType( 0.275, 0.750 ) ); + meshBuilder.setPoint( 6, PointType( 0.000, 0.250 ) ); + meshBuilder.setPoint( 7, PointType( 0.250, 0.000 ) ); + meshBuilder.setPoint( 8, PointType( 0.000, 0.000 ) ); + meshBuilder.setPoint( 9, PointType( 0.750, 0.000 ) ); + meshBuilder.setPoint( 10, PointType( 0.000, 0.750 ) ); + meshBuilder.setPoint( 11, PointType( 1.000, 0.500 ) ); + meshBuilder.setPoint( 12, PointType( 1.000, 0.000 ) ); + meshBuilder.setPoint( 13, PointType( 0.500, 1.000 ) ); + meshBuilder.setPoint( 14, PointType( 1.000, 1.000 ) ); + meshBuilder.setPoint( 15, PointType( 0.000, 1.000 ) ); + + /**** + * Setup the following polygons: + * + * 1 0 3 2 4 5 + * 8 7 0 1 6 + * 9 3 0 7 + * 6 1 5 10 + * 12 11 2 3 9 + * 13 4 2 11 14 + * 10 5 4 13 15 + */ + + meshBuilder.setCellCornersCounts( { 6, 5, 4, 4, 5, 5, 5 } ); + + // 1 0 3 2 4 5 + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); + + // 8 7 0 1 6 + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 8 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 7 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 0 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 3, 1 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 4, 6 ); + + // 9 3 0 7 + meshBuilder.getCellSeed( 2 ).setCornerId( 0, 9 ); + meshBuilder.getCellSeed( 2 ).setCornerId( 1, 3 ); + meshBuilder.getCellSeed( 2 ).setCornerId( 2, 0 ); + meshBuilder.getCellSeed( 2 ).setCornerId( 3, 7 ); + + // 6 1 5 10 + meshBuilder.getCellSeed( 3 ).setCornerId( 0, 6 ); + meshBuilder.getCellSeed( 3 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 3 ).setCornerId( 2, 5 ); + meshBuilder.getCellSeed( 3 ).setCornerId( 3, 10 ); + + // 12 11 2 3 9 + meshBuilder.getCellSeed( 4 ).setCornerId( 0, 12 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 1, 11 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 4 ).setCornerId( 4, 9 ); + + // 13 4 2 11 14 + meshBuilder.getCellSeed( 5 ).setCornerId( 0, 13 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 1, 4 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 3, 11 ); + meshBuilder.getCellSeed( 5 ).setCornerId( 4, 14 ); + + // 10 5 4 13 15 + meshBuilder.getCellSeed( 6 ).setCornerId( 0, 10 ); + meshBuilder.getCellSeed( 6 ).setCornerId( 1, 5 ); + meshBuilder.getCellSeed( 6 ).setCornerId( 2, 4 ); + meshBuilder.getCellSeed( 6 ).setCornerId( 3, 13 ); + meshBuilder.getCellSeed( 6 ).setCornerId( 4, 15 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + // tests for entities counts + EXPECT_EQ( mesh.getEntitiesCount< 2 >(), 7 ); + EXPECT_EQ( mesh.getEntitiesCount< 1 >(), 22 ); + EXPECT_EQ( mesh.getEntitiesCount< 0 >(), 16 ); + + // tests for the subentities layer + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSubentityIndex< 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSubentityIndex< 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSubentityIndex< 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSubentityIndex< 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSubentityIndex< 0 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSubentityIndex< 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSubentityIndex< 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSubentityIndex< 0 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSubentityIndex< 0 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSubentityIndex< 0 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSubentityIndex< 0 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSubentityIndex< 0 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSubentityIndex< 0 >( 0 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSubentityIndex< 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSubentityIndex< 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSubentityIndex< 0 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSubentityIndex< 0 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSubentityIndex< 0 >( 1 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSubentityIndex< 0 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSubentityIndex< 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSubentityIndex< 0 >( 0 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSubentityIndex< 0 >( 1 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSubentityIndex< 0 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSubentityIndex< 0 >( 1 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSubentityIndex< 0 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSubentityIndex< 0 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 14 ).template getSubentityIndex< 0 >( 0 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 14 ).template getSubentityIndex< 0 >( 1 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 15 ).template getSubentityIndex< 0 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 15 ).template getSubentityIndex< 0 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 16 ).template getSubentityIndex< 0 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 16 ).template getSubentityIndex< 0 >( 1 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSubentityIndex< 0 >( 0 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSubentityIndex< 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 18 ).template getSubentityIndex< 0 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 18 ).template getSubentityIndex< 0 >( 1 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 19 ).template getSubentityIndex< 0 >( 0 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 19 ).template getSubentityIndex< 0 >( 1 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 20 ).template getSubentityIndex< 0 >( 0 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 20 ).template getSubentityIndex< 0 >( 1 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 21 ).template getSubentityIndex< 0 >( 0 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 21 ).template getSubentityIndex< 0 >( 1 ), 10 ); + + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentitiesCount< 0 >( ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 2 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 3 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 4 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 5 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentitiesCount< 1 >( ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 4 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 5 ), 5 ); + + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 2 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 3 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 4 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 2 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 3 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 4 ), 9 ); + + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 2 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 3 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 2 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 3 ), 11 ); + + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 2 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 3 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 2 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 3 ), 13 ); + + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 0 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 1 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 4 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 0 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 1 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 3 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 4 ), 16 ); + + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 0 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 3 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 4 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 0 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 2 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 3 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 4 ), 19 ); + + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 2 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 3 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 4 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 0 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 2 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 3 ), 20 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 4 ), 21 ); + + // tests for the superentities layer + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 2 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 2 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 2 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 2 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 2 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 2 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 2 ), 10 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 2 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 2 ), 17 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 2 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 2 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 2 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 1 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 1 >( 1 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 1 >( 2 ), 13 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 1 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 1 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 1 >( 2 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentitiesCount< 1 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 1 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 1 >( 1 ), 9 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 1 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 1 >( 1 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 1 >( 2 ), 16 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 1 >( 0 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 1 >( 1 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 1 >( 2 ), 21 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 2 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 1 >( 0 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 1 >( 1 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 1 >( 2 ), 18 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 2 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 2 >( 1 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentitiesCount< 1 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 1 >( 0 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 1 >( 1 ), 16 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 2 >( 0 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 1 >( 0 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 1 >( 1 ), 19 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 1 >( 2 ), 20 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentitiesCount< 1 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentityIndex < 1 >( 0 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentityIndex < 1 >( 1 ), 19 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentitiesCount< 1 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentityIndex < 1 >( 0 ), 20 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentityIndex < 1 >( 1 ), 21 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentityIndex < 2 >( 0 ), 6 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 2 >( 1 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 2 >( 1 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentityIndex < 2 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentityIndex < 2 >( 0 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 14 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 14 ).template getSuperentityIndex < 2 >( 0 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 15 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 15 ).template getSuperentityIndex < 2 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 15 ).template getSuperentityIndex < 2 >( 1 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 16 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 16 ).template getSuperentityIndex < 2 >( 0 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 17 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 18 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 18 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 19 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 19 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 20 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 20 ).template getSuperentityIndex < 2 >( 0 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 21 ).template getSuperentitiesCount< 2 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 21 ).template getSuperentityIndex < 2 >( 0 ), 6 ); + + // tests for the dual graph layer + ASSERT_EQ( mesh.getNeighborCounts().getSize(), 7 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 0 ), 6 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 0, 0 ), 1 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 0, 1 ), 3 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 0, 2 ), 2 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 0, 3 ), 4 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 0, 4 ), 5 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 0, 5 ), 6 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 1 ), 3 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 1, 0 ), 2 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 1, 1 ), 0 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 1, 2 ), 3 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 2 ), 3 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 2, 0 ), 4 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 2, 1 ), 0 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 2, 2 ), 1 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 3 ), 3 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 3, 0 ), 1 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 3, 1 ), 0 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 3, 2 ), 6 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 4 ), 3 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 4, 0 ), 5 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 4, 1 ), 0 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 4, 2 ), 2 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 5 ), 3 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 5, 0 ), 6 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 5, 1 ), 0 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 5, 2 ), 4 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 6 ), 3 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 6, 0 ), 3 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 6, 1 ), 0 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 6, 2 ), 5 ); + + //Tags test for boundaries + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).getTag() & TNL::Meshes::EntityTags::BoundaryEntity, 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).getTag() & TNL::Meshes::EntityTags::BoundaryEntity, 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).getTag() & TNL::Meshes::EntityTags::BoundaryEntity, 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).getTag() & TNL::Meshes::EntityTags::BoundaryEntity, 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).getTag() & TNL::Meshes::EntityTags::BoundaryEntity, 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).getTag() & TNL::Meshes::EntityTags::BoundaryEntity, 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).getTag() & TNL::Meshes::EntityTags::BoundaryEntity, 1 ); + + testFinishedMesh( mesh ); +}; + +TEST( MeshTest, TwoWedgesTest ) +{ + using WedgeTestMesh = Mesh< TestTwoWedgesMeshConfig >; + using WedgeMeshEntityType = MeshEntity< TestTwoWedgesMeshConfig, Devices::Host, Topologies::Wedge >; + using PolygonMeshEntityType = typename WedgeMeshEntityType::SubentityTraits< 2 >::SubentityType; + using EdgeMeshEntityType = typename WedgeMeshEntityType::SubentityTraits< 1 >::SubentityType; + using VertexMeshEntityType = typename WedgeMeshEntityType::SubentityTraits< 0 >::SubentityType; + + static_assert( WedgeMeshEntityType::SubentityTraits< 2 >::storageEnabled, "Testing wedge entity does not store polygons as required." ); + static_assert( WedgeMeshEntityType::SubentityTraits< 1 >::storageEnabled, "Testing wedge entity does not store edges as required." ); + static_assert( WedgeMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing wedge entity does not store vertices as required." ); + + static_assert( PolygonMeshEntityType::SubentityTraits< 1 >::storageEnabled, "Testing polygon entity does not store edges as required." ); + static_assert( PolygonMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing polygon entity does not store vertices as required." ); + static_assert( PolygonMeshEntityType::SuperentityTraits< 3 >::storageEnabled, "Testing polygon entity does not store wedges as required." ); + + static_assert( EdgeMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing edge entity does not store vertices as required." ); + static_assert( EdgeMeshEntityType::SuperentityTraits< 3 >::storageEnabled, "Testing edge entity does not store wedges as required." ); + static_assert( EdgeMeshEntityType::SuperentityTraits< 2 >::storageEnabled, "Testing edge entity does not store polygons as required." ); + + static_assert( VertexMeshEntityType::SuperentityTraits< 3 >::storageEnabled, "Testing vertex entity does not store wedges as required." ); + static_assert( VertexMeshEntityType::SuperentityTraits< 2 >::storageEnabled, "Testing vertex entity does not store triangles as required." ); + static_assert( VertexMeshEntityType::SuperentityTraits< 1 >::storageEnabled, "Testing vertex entity does not store edges as required." ); + + using PointType = typename VertexMeshEntityType::PointType; + static_assert( std::is_same< PointType, Containers::StaticVector< 3, RealType > >::value, + "unexpected PointType" ); + + PointType point0( 1.0, 0.0, 0.0 ), + point1( 1.0, 0.0, 1.0 ), + point2( 1.0, 1.0, 0.5 ), + point3( 0.0, 0.0, 0.0 ), + point4( 0.0, 0.0, 1.0 ), + point5( 0.0, 1.0, 0.5 ), + point6( 1.0, -1.0, 0.5 ), + point7( 0.0, -1.0, 0.5 ); + + WedgeTestMesh mesh; + MeshBuilder< WedgeTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 8, 2 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + meshBuilder.setPoint( 5, point5 ); + meshBuilder.setPoint( 6, point6 ); + meshBuilder.setPoint( 7, point7 ); + + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); + + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 6 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 4, 4 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 5, 7 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + + // tests for entities counts + EXPECT_EQ( mesh.getEntitiesCount< 3 >(), 2 ); + EXPECT_EQ( mesh.getEntitiesCount< 2 >(), 9 ); + EXPECT_EQ( mesh.getEntitiesCount< 1 >(), 14 ); + EXPECT_EQ( mesh.getEntitiesCount< 0 >(), 8 ); + + + // tests for the subentities layer + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSubentityIndex< 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSubentityIndex< 0 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSubentityIndex< 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSubentityIndex< 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSubentityIndex< 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSubentityIndex< 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSubentityIndex< 0 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSubentityIndex< 0 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSubentityIndex< 0 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSubentityIndex< 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSubentityIndex< 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSubentityIndex< 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSubentityIndex< 0 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSubentityIndex< 0 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSubentityIndex< 0 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSubentityIndex< 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSubentityIndex< 0 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSubentityIndex< 0 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSubentityIndex< 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSubentityIndex< 0 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSubentityIndex< 0 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSubentityIndex< 0 >( 0 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSubentityIndex< 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSubentityIndex< 0 >( 0 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSubentityIndex< 0 >( 1 ), 6 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 2 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 2 ), 2 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 2 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 2 ), 5 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 3 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 2 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 3 ), 5 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 3 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 2 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 3 ), 4 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 2 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 3 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 2 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 3 ), 3 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 2 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 1 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 2 ), 10 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 2 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 1 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 2 ), 12 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 0 >( 2 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 0 >( 3 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 1 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 1 >( 1 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 1 >( 2 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 1 >( 3 ), 12 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 0 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 0 >( 2 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 0 >( 3 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 1 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 1 >( 1 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 1 >( 2 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 1 >( 3 ), 11 ); + + ASSERT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentitiesCount< 0 >( ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 4 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 5 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentitiesCount< 1 >( ), 9 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 4 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 5 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 6 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 7 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 8 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 2 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 2 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 2 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 2 >( 4 ), 4 ); + + ASSERT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentitiesCount< 0 >( ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 2 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 4 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 5 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentitiesCount< 1 >( ), 9 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 1 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 2 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 4 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 5 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 6 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 7 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 8 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 2 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 2 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 2 >( 2 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 2 >( 3 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 2 >( 4 ), 4 ); + + + // tests for the superentities layer + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 2 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 3 ), 10 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 2 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 3 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 4 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 2 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 3 ), 9 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 2 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 3 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 4 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 2 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 2 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 2 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 3 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 2 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 3 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 4 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 2 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 3 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 2 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 3 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 4 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 2 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 2 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 1 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 1 >( 1 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 1 >( 2 ), 13 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 2 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 2 >( 2 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 1 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 1 >( 1 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 1 >( 2 ), 13 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 2 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 2 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 2 >( 2 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 2 >( 2 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 2 >( 2 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 2 >( 2 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentityIndex < 2 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentityIndex < 2 >( 2 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentityIndex < 2 >( 1 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentityIndex < 2 >( 1 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentityIndex < 2 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentityIndex < 2 >( 1 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentityIndex < 2 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentityIndex < 2 >( 1 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentityIndex < 2 >( 0 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentityIndex < 2 >( 1 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 0 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 1 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 2 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 3 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 4 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 5 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 6 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 7 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 8 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + + // tests for the dual graph layer + ASSERT_EQ( mesh.getNeighborCounts().getSize(), 2 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 0 ), 1 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 0, 0 ), 1 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 1 ), 1 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 1, 0 ), 0 ); + + testFinishedMesh( mesh ); +} + +TEST( MeshTest, TwoPyramidsTest ) +{ + using PyramidTestMesh = Mesh< TestTwoPyramidsMeshConfig >; + using PyramidMeshEntityType = MeshEntity< TestTwoPyramidsMeshConfig, Devices::Host, Topologies::Pyramid >; + using PolygonMeshEntityType = typename PyramidMeshEntityType::SubentityTraits< 2 >::SubentityType; + using EdgeMeshEntityType = typename PyramidMeshEntityType::SubentityTraits< 1 >::SubentityType; + using VertexMeshEntityType = typename PyramidMeshEntityType::SubentityTraits< 0 >::SubentityType; + + static_assert( PyramidMeshEntityType::SubentityTraits< 2 >::storageEnabled, "Testing pyramid entity does not store polygons as required." ); + static_assert( PyramidMeshEntityType::SubentityTraits< 1 >::storageEnabled, "Testing pyramid entity does not store edges as required." ); + static_assert( PyramidMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing pyramid entity does not store vertices as required." ); + + static_assert( PolygonMeshEntityType::SubentityTraits< 1 >::storageEnabled, "Testing polygon entity does not store edges as required." ); + static_assert( PolygonMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing polygon entity does not store vertices as required." ); + static_assert( PolygonMeshEntityType::SuperentityTraits< 3 >::storageEnabled, "Testing polygon entity does not store pyramids as required." ); + + static_assert( EdgeMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing edge entity does not store vertices as required." ); + static_assert( EdgeMeshEntityType::SuperentityTraits< 3 >::storageEnabled, "Testing edge entity does not store pyramids as required." ); + static_assert( EdgeMeshEntityType::SuperentityTraits< 2 >::storageEnabled, "Testing edge entity does not store polygons as required." ); + + static_assert( VertexMeshEntityType::SuperentityTraits< 3 >::storageEnabled, "Testing vertex entity does not store pyramids as required." ); + static_assert( VertexMeshEntityType::SuperentityTraits< 2 >::storageEnabled, "Testing vertex entity does not store triangles as required." ); + static_assert( VertexMeshEntityType::SuperentityTraits< 1 >::storageEnabled, "Testing vertex entity does not store edges as required." ); + + using PointType = typename VertexMeshEntityType::PointType; + static_assert( std::is_same< PointType, Containers::StaticVector< 3, RealType > >::value, + "unexpected PointType" ); + + PointType point0( 0.0, 0.0, 0.0 ), + point1( 1.0, 0.0, 0.0 ), + point2( 1.0, 0.0, 1.0 ), + point3( 0.0, 0.0, 1.0 ), + point4( 0.5, 1.0, 0.5 ), + point5( 0.5, -1.0, 0.5 ); + + PyramidTestMesh mesh; + MeshBuilder< PyramidTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 6, 2 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + meshBuilder.setPoint( 5, point5 ); + + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 4, 5 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + + // tests for entities counts + EXPECT_EQ( mesh.getEntitiesCount< 3 >(), 2 ); + EXPECT_EQ( mesh.getEntitiesCount< 2 >(), 9 ); + EXPECT_EQ( mesh.getEntitiesCount< 1 >(), 12 ); + EXPECT_EQ( mesh.getEntitiesCount< 0 >(), 6 ); + + + // tests for the subentities layer + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSubentityIndex< 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSubentityIndex< 0 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSubentityIndex< 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSubentityIndex< 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSubentityIndex< 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSubentityIndex< 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSubentityIndex< 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSubentityIndex< 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSubentityIndex< 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSubentityIndex< 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSubentityIndex< 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSubentityIndex< 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSubentityIndex< 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSubentityIndex< 0 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSubentityIndex< 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSubentityIndex< 0 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSubentityIndex< 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSubentityIndex< 0 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSubentityIndex< 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSubentityIndex< 0 >( 1 ), 5 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 0 >( 3 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex < 1 >( 3 ), 3 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 0 >( 2 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex < 1 >( 2 ), 4 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 0 >( 2 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex < 1 >( 2 ), 5 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 0 >( 2 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex < 1 >( 2 ), 6 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 0 >( 2 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex < 1 >( 2 ), 7 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 0 >( 2 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 1 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex < 1 >( 2 ), 8 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 0 >( 2 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 1 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex < 1 >( 2 ), 9 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 0 >( 2 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 1 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 1 >( 1 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex < 1 >( 2 ), 10 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 0 >( 2 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 1 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 1 >( 1 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex < 1 >( 2 ), 11 ); + + ASSERT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 0 >( 4 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentitiesCount< 1 >( ), 8 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 4 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 5 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 6 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 1 >( 7 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 2 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 2 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 2 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex < 2 >( 4 ), 4 ); + + ASSERT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 0 >( 4 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentitiesCount< 1 >( ), 8 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 4 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 5 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 6 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 1 >( 7 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 2 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 2 >( 2 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 2 >( 3 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex < 2 >( 4 ), 8 ); + + + // tests for the superentities layer + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 2 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 3 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 2 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 3 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 4 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 2 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 3 ), 9 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 3 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 4 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 2 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 3 ), 10 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 2 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 3 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 4 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 2 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 3 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 2 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 3 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 4 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 2 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 3 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 2 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 2 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 3 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 1 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 2 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 3 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 2 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 2 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 3 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 2 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 2 >( 2 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 2 >( 2 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 2 >( 2 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 2 >( 2 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 2 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 0 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 1 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 2 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 3 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 4 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 5 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 6 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 7 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 8 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + + // tests for the dual graph layer + ASSERT_EQ( mesh.getNeighborCounts().getSize(), 2 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 0 ), 1 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 0, 0 ), 1 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 1 ), 1 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 1, 0 ), 0 ); + + testFinishedMesh( mesh ); +} + +TEST( MeshTest, TwoPolyhedronsTest ) +{ + using PolyhedronTestMesh = Mesh< TestTwoPolyhedronsMeshConfig >; + using PolyhedronMeshEntityType = MeshEntity< TestTwoPolyhedronsMeshConfig, Devices::Host, Topologies::Polyhedron >; + using PolygonMeshEntityType = typename PolyhedronMeshEntityType::SubentityTraits< 2 >::SubentityType; + using EdgeMeshEntityType = typename PolyhedronMeshEntityType::SubentityTraits< 1 >::SubentityType; + using VertexMeshEntityType = typename PolyhedronMeshEntityType::SubentityTraits< 0 >::SubentityType; + + static_assert( PolyhedronMeshEntityType::SubentityTraits< 2 >::storageEnabled, "Testing polyhedron entity does not store polygons as required." ); + static_assert( PolyhedronMeshEntityType::SubentityTraits< 1 >::storageEnabled, "Testing polyhedron entity does not store edges as required." ); + static_assert( PolyhedronMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing polyhedron entity does not store vertices as required." ); + + static_assert( PolygonMeshEntityType::SubentityTraits< 1 >::storageEnabled, "Testing polygon entity does not store edges as required." ); + static_assert( PolygonMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing polygon entity does not store vertices as required." ); + static_assert( PolygonMeshEntityType::SuperentityTraits< 3 >::storageEnabled, "Testing polygon entity does not store pyramids as required." ); + + static_assert( EdgeMeshEntityType::SubentityTraits< 0 >::storageEnabled, "Testing edge entity does not store vertices as required." ); + static_assert( EdgeMeshEntityType::SuperentityTraits< 3 >::storageEnabled, "Testing edge entity does not store pyramids as required." ); + static_assert( EdgeMeshEntityType::SuperentityTraits< 2 >::storageEnabled, "Testing edge entity does not store polygons as required." ); + + static_assert( VertexMeshEntityType::SuperentityTraits< 3 >::storageEnabled, "Testing vertex entity does not store pyramids as required." ); + static_assert( VertexMeshEntityType::SuperentityTraits< 2 >::storageEnabled, "Testing vertex entity does not store triangles as required." ); + static_assert( VertexMeshEntityType::SuperentityTraits< 1 >::storageEnabled, "Testing vertex entity does not store edges as required." ); + + using PointType = typename VertexMeshEntityType::PointType; + static_assert( std::is_same< PointType, Containers::StaticVector< 3, RealType > >::value, + "unexpected PointType" ); + + PointType point0 ( -1.25000, 1.16650, 1.20300 ), + point1 ( -1.20683, 1.16951, 1.20537 ), + point2 ( -1.16843, 1.19337, 1.17878 ), + point3 ( -1.21025, 1.21901, 1.15383 ), + point4 ( -1.25000, 1.21280, 1.15670 ), + point5 ( -1.20816, 1.25000, 1.16756 ), + point6 ( -1.25000, 1.25000, 1.18056 ), + point7 ( -1.14802, 1.21553, 1.21165 ), + point8 ( -1.16186, 1.25000, 1.21385 ), + point9 ( -1.20307, 1.17486, 1.25000 ), + point10( -1.25000, 1.18056, 1.25000 ), + point11( -1.15677, 1.22115, 1.25000 ), + point12( -1.18056, 1.25000, 1.25000 ), + point13( -1.25000, 1.25000, 1.25000 ), + point14( -1.09277, 1.20806, 1.19263 ), + point15( -1.07219, 1.22167, 1.17994 ), + point16( -1.07215, 1.25000, 1.18679 ), + point17( -1.05697, 1.21124, 1.19697 ), + point18( -1.04607, 1.21508, 1.22076 ), + point19( -1.02140, 1.25000, 1.22293 ), + point20( -1.06418, 1.22115, 1.25000 ), + point21( -1.04167, 1.25000, 1.25000 ); + + PolyhedronTestMesh mesh; + MeshBuilder< PolyhedronTestMesh > meshBuilder; + + meshBuilder.setEntitiesCount( 22, 2, 16 ); + + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + meshBuilder.setPoint( 5, point5 ); + meshBuilder.setPoint( 6, point6 ); + meshBuilder.setPoint( 7, point7 ); + meshBuilder.setPoint( 8, point8 ); + meshBuilder.setPoint( 9, point9 ); + meshBuilder.setPoint( 10, point10 ); + meshBuilder.setPoint( 11, point11 ); + meshBuilder.setPoint( 12, point12 ); + meshBuilder.setPoint( 13, point13 ); + meshBuilder.setPoint( 14, point14 ); + meshBuilder.setPoint( 15, point15 ); + meshBuilder.setPoint( 16, point16 ); + meshBuilder.setPoint( 17, point17 ); + meshBuilder.setPoint( 18, point18 ); + meshBuilder.setPoint( 19, point19 ); + meshBuilder.setPoint( 20, point20 ); + meshBuilder.setPoint( 21, point21 ); + + /**** + * Setup the following faces (polygons): + * + * 0 1 2 3 4 + * 4 3 5 6 + * 5 3 2 7 8 + * 9 1 0 10 + * 11 7 2 1 9 + * 8 7 11 12 + * 13 12 11 9 10 + * 13 10 0 4 6 + * 13 6 5 8 12 + * 8 7 14 15 16 + * 16 15 17 18 19 + * 20 18 17 14 7 11 + * 17 15 14 + * 21 19 18 20 + * 21 20 11 12 + * 12 8 16 19 21 + * + * NOTE: indices refer to the points + */ + + meshBuilder.setFaceCornersCounts( { 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 6, 3, 4, 4, 5 } ); + + // 0 1 2 3 4 + meshBuilder.getFaceSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getFaceSeed( 0 ).setCornerId( 4, 4 ); + + // 4 3 5 6 + meshBuilder.getFaceSeed( 1 ).setCornerId( 0, 4 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 1, 3 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 2, 5 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 3, 6 ); + + // 5 3 2 7 8 + meshBuilder.getFaceSeed( 2 ).setCornerId( 0, 5 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 1, 3 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 3, 7 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 4, 8 ); + + // 9 1 0 10 + meshBuilder.getFaceSeed( 3 ).setCornerId( 0, 9 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 2, 0 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 3, 10 ); + + // 11 7 2 1 9 + meshBuilder.getFaceSeed( 4 ).setCornerId( 0, 11 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 3, 1 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 4, 9 ); + + // 8 7 11 12 + meshBuilder.getFaceSeed( 5 ).setCornerId( 0, 8 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 2, 11 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 3, 12 ); + + // 13 12 11 9 10 + meshBuilder.getFaceSeed( 6 ).setCornerId( 0, 13 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 1, 12 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 2, 11 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 3, 9 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 4, 10 ); + + // 13 10 0 4 6 + meshBuilder.getFaceSeed( 7 ).setCornerId( 0, 13 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 1, 10 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 2, 0 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 3, 4 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 4, 6 ); + + // 13 6 5 8 12 + meshBuilder.getFaceSeed( 8 ).setCornerId( 0, 13 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 1, 6 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 5 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 3, 8 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 4, 12 ); + + // 8 7 14 15 16 + meshBuilder.getFaceSeed( 9 ).setCornerId( 0, 8 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 2, 14 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 3, 15 ); + meshBuilder.getFaceSeed( 9 ).setCornerId( 4, 16 ); + + // 16 15 17 18 19 + meshBuilder.getFaceSeed( 10 ).setCornerId( 0, 16 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 1, 15 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 2, 17 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 3, 18 ); + meshBuilder.getFaceSeed( 10 ).setCornerId( 4, 19 ); + + // 20 18 17 14 7 11 + meshBuilder.getFaceSeed( 11 ).setCornerId( 0, 20 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 1, 18 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 2, 17 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 3, 14 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 4, 7 ); + meshBuilder.getFaceSeed( 11 ).setCornerId( 5, 11 ); + + // 17 15 14 + meshBuilder.getFaceSeed( 12 ).setCornerId( 0, 17 ); + meshBuilder.getFaceSeed( 12 ).setCornerId( 1, 15 ); + meshBuilder.getFaceSeed( 12 ).setCornerId( 2, 14 ); + + // 21 19 18 20 + meshBuilder.getFaceSeed( 13 ).setCornerId( 0, 21 ); + meshBuilder.getFaceSeed( 13 ).setCornerId( 1, 19 ); + meshBuilder.getFaceSeed( 13 ).setCornerId( 2, 18 ); + meshBuilder.getFaceSeed( 13 ).setCornerId( 3, 20 ); + + // 21 20 11 12 + meshBuilder.getFaceSeed( 14 ).setCornerId( 0, 21 ); + meshBuilder.getFaceSeed( 14 ).setCornerId( 1, 20 ); + meshBuilder.getFaceSeed( 14 ).setCornerId( 2, 11 ); + meshBuilder.getFaceSeed( 14 ).setCornerId( 3, 12 ); + + // 12 8 16 19 21 + meshBuilder.getFaceSeed( 15 ).setCornerId( 0, 12 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 1, 8 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 2, 16 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 3, 19 ); + meshBuilder.getFaceSeed( 15 ).setCornerId( 4, 21 ); + + /**** + * Setup the following cells (polyhedrons): + * + * 0 1 2 3 4 5 6 7 8 + * 9 10 11 12 13 5 14 15 + * + * NOTE: indices refer to the faces + */ + + meshBuilder.setCellCornersCounts( { 9, 8 } ); + + // 0 1 2 3 4 5 6 7 8 + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 6, 6 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 7, 7 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 8, 8 ); + + // 9 10 11 12 13 5 14 15 + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 9 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 10 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 11 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 3, 12 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 4, 13 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 5, 5 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 6, 14 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 7, 15 ); + + ASSERT_TRUE( meshBuilder.build( mesh ) ); + + // tests for entities counts + EXPECT_EQ( mesh.getEntitiesCount< 3 >(), 2 ); + EXPECT_EQ( mesh.getEntitiesCount< 2 >(), 16 ); + EXPECT_EQ( mesh.getEntitiesCount< 1 >(), 35 ); + EXPECT_EQ( mesh.getEntitiesCount< 0 >(), 22 ); + + // tests for the subentities layer + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSubentityIndex< 0 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSubentityIndex< 0 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSubentityIndex< 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSubentityIndex< 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSubentityIndex< 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSubentityIndex< 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSubentityIndex< 0 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSubentityIndex< 0 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSubentityIndex< 0 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSubentityIndex< 0 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSubentityIndex< 0 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSubentityIndex< 0 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSubentityIndex< 0 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSubentityIndex< 0 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSubentityIndex< 0 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSubentityIndex< 0 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSubentityIndex< 0 >( 0 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSubentityIndex< 0 >( 1 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSubentityIndex< 0 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSubentityIndex< 0 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSubentityIndex< 0 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSubentityIndex< 0 >( 1 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSubentityIndex< 0 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSubentityIndex< 0 >( 1 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 14 ).template getSubentityIndex< 0 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 14 ).template getSubentityIndex< 0 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 15 ).template getSubentityIndex< 0 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 15 ).template getSubentityIndex< 0 >( 1 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 16 ).template getSubentityIndex< 0 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 16 ).template getSubentityIndex< 0 >( 1 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSubentityIndex< 0 >( 0 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSubentityIndex< 0 >( 1 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 18 ).template getSubentityIndex< 0 >( 0 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 18 ).template getSubentityIndex< 0 >( 1 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 19 ).template getSubentityIndex< 0 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 19 ).template getSubentityIndex< 0 >( 1 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 20 ).template getSubentityIndex< 0 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 20 ).template getSubentityIndex< 0 >( 1 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 21 ).template getSubentityIndex< 0 >( 0 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 21 ).template getSubentityIndex< 0 >( 1 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 22 ).template getSubentityIndex< 0 >( 0 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 22 ).template getSubentityIndex< 0 >( 1 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 23 ).template getSubentityIndex< 0 >( 0 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 23 ).template getSubentityIndex< 0 >( 1 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 24 ).template getSubentityIndex< 0 >( 0 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 24 ).template getSubentityIndex< 0 >( 1 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 25 ).template getSubentityIndex< 0 >( 0 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 25 ).template getSubentityIndex< 0 >( 1 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 26 ).template getSubentityIndex< 0 >( 0 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 26 ).template getSubentityIndex< 0 >( 1 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 27 ).template getSubentityIndex< 0 >( 0 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 27 ).template getSubentityIndex< 0 >( 1 ), 19 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 28 ).template getSubentityIndex< 0 >( 0 ), 19 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 28 ).template getSubentityIndex< 0 >( 1 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 29 ).template getSubentityIndex< 0 >( 0 ), 20 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 29 ).template getSubentityIndex< 0 >( 1 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 30 ).template getSubentityIndex< 0 >( 0 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 30 ).template getSubentityIndex< 0 >( 1 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 31 ).template getSubentityIndex< 0 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 31 ).template getSubentityIndex< 0 >( 1 ), 20 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 32 ).template getSubentityIndex< 0 >( 0 ), 21 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 32 ).template getSubentityIndex< 0 >( 1 ), 19 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 33 ).template getSubentityIndex< 0 >( 0 ), 20 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 33 ).template getSubentityIndex< 0 >( 1 ), 21 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 34 ).template getSubentityIndex< 0 >( 0 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 34 ).template getSubentityIndex< 0 >( 1 ), 21 ); + + + ASSERT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 0 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 0 >( 4 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 1 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 1 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSubentityIndex< 1 >( 4 ), 4 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 0 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 0 >( 2 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 0 >( 3 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 1 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 1 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 1 >( 2 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSubentityIndex< 1 >( 3 ), 7 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex< 0 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex< 0 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex< 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex< 0 >( 3 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex< 0 >( 4 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex< 1 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex< 1 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex< 1 >( 2 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex< 1 >( 3 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSubentityIndex< 1 >( 4 ), 10 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex< 0 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex< 0 >( 2 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex< 0 >( 3 ), 10 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex< 1 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex< 1 >( 1 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex< 1 >( 2 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSubentityIndex< 1 >( 3 ), 13 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex< 0 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex< 0 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex< 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex< 0 >( 3 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex< 0 >( 4 ), 9 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex< 1 >( 0 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex< 1 >( 1 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex< 1 >( 2 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex< 1 >( 3 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSubentityIndex< 1 >( 4 ), 15 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex< 0 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex< 0 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex< 0 >( 2 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex< 0 >( 3 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex< 1 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex< 1 >( 1 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex< 1 >( 2 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSubentityIndex< 1 >( 3 ), 17 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex< 0 >( 0 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex< 0 >( 1 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex< 0 >( 2 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex< 0 >( 3 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex< 0 >( 4 ), 10 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex< 1 >( 0 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex< 1 >( 1 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex< 1 >( 2 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex< 1 >( 3 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSubentityIndex< 1 >( 4 ), 19 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex< 0 >( 0 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex< 0 >( 1 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex< 0 >( 2 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex< 0 >( 3 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex< 0 >( 4 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex< 1 >( 0 ), 19 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex< 1 >( 1 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex< 1 >( 2 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex< 1 >( 3 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSubentityIndex< 1 >( 4 ), 20 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex< 0 >( 0 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex< 0 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex< 0 >( 2 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex< 0 >( 3 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex< 0 >( 4 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex< 1 >( 0 ), 20 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex< 1 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex< 1 >( 2 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex< 1 >( 3 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSubentityIndex< 1 >( 4 ), 18 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentityIndex< 0 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentityIndex< 0 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentityIndex< 0 >( 2 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentityIndex< 0 >( 3 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentityIndex< 0 >( 4 ), 16 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentityIndex< 1 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentityIndex< 1 >( 1 ), 21 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentityIndex< 1 >( 2 ), 22 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentityIndex< 1 >( 3 ), 23 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSubentityIndex< 1 >( 4 ), 24 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentityIndex< 0 >( 0 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentityIndex< 0 >( 1 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentityIndex< 0 >( 2 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentityIndex< 0 >( 3 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentityIndex< 0 >( 4 ), 19 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentityIndex< 1 >( 0 ), 23 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentityIndex< 1 >( 1 ), 25 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentityIndex< 1 >( 2 ), 26 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentityIndex< 1 >( 3 ), 27 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSubentityIndex< 1 >( 4 ), 28 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentitiesCount< 0 >( ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 0 >( 0 ), 20 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 0 >( 1 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 0 >( 2 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 0 >( 3 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 0 >( 4 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 0 >( 5 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentitiesCount< 1 >( ), 6 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 1 >( 0 ), 29 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 1 >( 1 ), 26 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 1 >( 2 ), 30 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 1 >( 3 ), 21 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 1 >( 4 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSubentityIndex< 1 >( 5 ), 31 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 12 ).template getSubentitiesCount< 0 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 12 ).template getSubentityIndex< 0 >( 0 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 12 ).template getSubentityIndex< 0 >( 1 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 12 ).template getSubentityIndex< 0 >( 2 ), 14 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 12 ).template getSubentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 12 ).template getSubentityIndex< 1 >( 0 ), 25 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 12 ).template getSubentityIndex< 1 >( 1 ), 22 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 12 ).template getSubentityIndex< 1 >( 2 ), 30 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 13 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 13 ).template getSubentityIndex< 0 >( 0 ), 21 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 13 ).template getSubentityIndex< 0 >( 1 ), 19 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 13 ).template getSubentityIndex< 0 >( 2 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 13 ).template getSubentityIndex< 0 >( 3 ), 20 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 13 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 13 ).template getSubentityIndex< 1 >( 0 ), 32 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 13 ).template getSubentityIndex< 1 >( 1 ), 27 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 13 ).template getSubentityIndex< 1 >( 2 ), 29 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 13 ).template getSubentityIndex< 1 >( 3 ), 33 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 14 ).template getSubentitiesCount< 0 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 14 ).template getSubentityIndex< 0 >( 0 ), 21 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 14 ).template getSubentityIndex< 0 >( 1 ), 20 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 14 ).template getSubentityIndex< 0 >( 2 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 14 ).template getSubentityIndex< 0 >( 3 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 14 ).template getSubentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 14 ).template getSubentityIndex< 1 >( 0 ), 33 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 14 ).template getSubentityIndex< 1 >( 1 ), 31 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 14 ).template getSubentityIndex< 1 >( 2 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 14 ).template getSubentityIndex< 1 >( 3 ), 34 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentitiesCount< 0 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentityIndex< 0 >( 0 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentityIndex< 0 >( 1 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentityIndex< 0 >( 2 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentityIndex< 0 >( 3 ), 19 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentityIndex< 0 >( 4 ), 21 ); + ASSERT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentitiesCount< 1 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentityIndex< 1 >( 0 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentityIndex< 1 >( 1 ), 24 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentityIndex< 1 >( 2 ), 28 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentityIndex< 1 >( 3 ), 32 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSubentityIndex< 1 >( 4 ), 34 ); + + + ASSERT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentitiesCount< 0 >( ), 14 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 4 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 5 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 6 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 7 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 8 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 9 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 10 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 11 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 12 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 0 >( 13 ), 13 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentitiesCount< 1 >( ), 21 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 4 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 5 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 6 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 7 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 8 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 9 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 10 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 11 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 12 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 13 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 14 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 15 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 16 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 17 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 18 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 19 ), 19 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 1 >( 20 ), 20 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentitiesCount< 2 >( ), 9 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 2 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 2 >( 2 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 2 >( 3 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 2 >( 4 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 2 >( 5 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 2 >( 6 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 2 >( 7 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 0 ).template getSubentityIndex< 2 >( 8 ), 8 ); + + ASSERT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentitiesCount< 0 >( ), 12 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 2 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 3 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 4 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 5 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 6 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 7 ), 19 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 8 ), 20 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 9 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 10 ), 21 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 0 >( 11 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentitiesCount< 1 >( ), 18 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 1 ), 21 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 2 ), 22 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 3 ), 23 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 4 ), 24 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 5 ), 25 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 6 ), 26 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 7 ), 27 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 8 ), 28 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 9 ), 29 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 10 ), 30 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 11 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 12 ), 31 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 13 ), 32 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 14 ), 33 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 15 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 16 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 1 >( 17 ), 34 ); + ASSERT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentitiesCount< 2 >( ), 8 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 2 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 2 >( 1 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 2 >( 2 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 2 >( 3 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 2 >( 4 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 2 >( 5 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 2 >( 6 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 3 >( 1 ).template getSubentityIndex< 2 >( 7 ), 15 ); + + + // tests for the superentities layer + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 1 >( 2 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 2 >( 2 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 0 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 1 >( 2 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 2 >( 2 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 1 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 1 >( 2 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 2 >( 2 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 2 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 1 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 1 >( 2 ), 5 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 2 >( 2 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 3 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 1 >( 2 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 1 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 2 >( 2 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 4 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 1 >( 2 ), 10 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 2 >( 2 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 5 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 1 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 1 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 1 >( 2 ), 20 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 2 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 2 >( 2 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 6 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 1 >( 0 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 1 >( 1 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 1 >( 2 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 1 >( 3 ), 21 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 2 >( 2 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 2 >( 3 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 2 >( 4 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 7 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 1 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 1 >( 1 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 1 >( 2 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 1 >( 3 ), 24 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 2 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 2 >( 2 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 2 >( 3 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 2 >( 4 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 8 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 1 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 1 >( 1 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 1 >( 2 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 2 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 2 >( 2 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 9 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 1 >( 0 ), 12 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 1 >( 1 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 1 >( 2 ), 19 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 2 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 2 >( 2 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 10 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 1 >( 0 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 1 >( 1 ), 15 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 1 >( 2 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 1 >( 3 ), 31 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 2 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 2 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 2 >( 2 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 2 >( 3 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 2 >( 4 ), 14 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 11 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentitiesCount< 1 >( ), 4 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 1 >( 0 ), 16 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 1 >( 1 ), 17 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 1 >( 2 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 1 >( 3 ), 34 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentitiesCount< 2 >( ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 2 >( 2 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 2 >( 3 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 2 >( 4 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 12 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 1 >( 0 ), 18 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 1 >( 1 ), 19 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 1 >( 2 ), 20 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 2 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 2 >( 1 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 2 >( 2 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 13 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentityIndex < 1 >( 0 ), 21 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentityIndex < 1 >( 1 ), 22 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentityIndex < 1 >( 2 ), 30 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentityIndex < 2 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentityIndex < 2 >( 1 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentityIndex < 2 >( 2 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 14 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentityIndex < 1 >( 0 ), 22 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentityIndex < 1 >( 1 ), 23 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentityIndex < 1 >( 2 ), 25 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentityIndex < 2 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentityIndex < 2 >( 1 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentityIndex < 2 >( 2 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 15 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 16 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 16 ).template getSuperentityIndex < 1 >( 0 ), 23 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 16 ).template getSuperentityIndex < 1 >( 1 ), 24 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 16 ).template getSuperentityIndex < 1 >( 2 ), 28 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 16 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 16 ).template getSuperentityIndex < 2 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 16 ).template getSuperentityIndex < 2 >( 1 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 16 ).template getSuperentityIndex < 2 >( 2 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 16 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 16 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 17 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 17 ).template getSuperentityIndex < 1 >( 0 ), 25 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 17 ).template getSuperentityIndex < 1 >( 1 ), 26 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 17 ).template getSuperentityIndex < 1 >( 2 ), 30 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 17 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 17 ).template getSuperentityIndex < 2 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 17 ).template getSuperentityIndex < 2 >( 1 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 17 ).template getSuperentityIndex < 2 >( 2 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 17 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 17 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 18 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 18 ).template getSuperentityIndex < 1 >( 0 ), 26 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 18 ).template getSuperentityIndex < 1 >( 1 ), 27 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 18 ).template getSuperentityIndex < 1 >( 2 ), 29 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 18 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 18 ).template getSuperentityIndex < 2 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 18 ).template getSuperentityIndex < 2 >( 1 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 18 ).template getSuperentityIndex < 2 >( 2 ), 13 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 18 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 18 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 19 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 19 ).template getSuperentityIndex < 1 >( 0 ), 27 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 19 ).template getSuperentityIndex < 1 >( 1 ), 28 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 19 ).template getSuperentityIndex < 1 >( 2 ), 32 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 19 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 19 ).template getSuperentityIndex < 2 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 19 ).template getSuperentityIndex < 2 >( 1 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 19 ).template getSuperentityIndex < 2 >( 2 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 19 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 19 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 20 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 20 ).template getSuperentityIndex < 1 >( 0 ), 29 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 20 ).template getSuperentityIndex < 1 >( 1 ), 31 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 20 ).template getSuperentityIndex < 1 >( 2 ), 33 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 20 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 20 ).template getSuperentityIndex < 2 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 20 ).template getSuperentityIndex < 2 >( 1 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 20 ).template getSuperentityIndex < 2 >( 2 ), 14 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 20 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 20 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 0 >( 21 ).template getSuperentitiesCount< 1 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 21 ).template getSuperentityIndex < 1 >( 0 ), 32 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 21 ).template getSuperentityIndex < 1 >( 1 ), 33 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 21 ).template getSuperentityIndex < 1 >( 2 ), 34 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 21 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 21 ).template getSuperentityIndex < 2 >( 0 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 21 ).template getSuperentityIndex < 2 >( 1 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 21 ).template getSuperentityIndex < 2 >( 2 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 0 >( 21 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 0 >( 21 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + + ASSERT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 2 >( 1 ), 3 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 0 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 1 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 2 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 2 >( 1 ), 1 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 3 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 2 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 2 >( 1 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 4 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 2 >( 1 ), 2 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 5 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 2 >( 1 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 6 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 2 >( 0 ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 2 >( 1 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 7 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 8 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentityIndex < 2 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentityIndex < 2 >( 2 ), 9 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 9 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentityIndex < 2 >( 0 ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentityIndex < 2 >( 1 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 10 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentityIndex < 2 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentityIndex < 2 >( 1 ), 4 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 11 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentityIndex < 2 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentityIndex < 2 >( 1 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 12 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentityIndex < 2 >( 0 ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 13 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 14 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 14 ).template getSuperentityIndex < 2 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 14 ).template getSuperentityIndex < 2 >( 1 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 14 ).template getSuperentityIndex < 2 >( 2 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 14 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 14 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 14 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 15 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 15 ).template getSuperentityIndex < 2 >( 0 ), 4 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 15 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 15 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 15 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 16 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 16 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 16 ).template getSuperentityIndex < 2 >( 1 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 16 ).template getSuperentityIndex < 2 >( 2 ), 14 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 16 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 16 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 16 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 17 ).template getSuperentitiesCount< 2 >( ), 3 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSuperentityIndex < 2 >( 0 ), 5 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSuperentityIndex < 2 >( 1 ), 8 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSuperentityIndex < 2 >( 2 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 17 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 17 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 18 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 18 ).template getSuperentityIndex < 2 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 18 ).template getSuperentityIndex < 2 >( 1 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 18 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 18 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 19 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 19 ).template getSuperentityIndex < 2 >( 0 ), 6 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 19 ).template getSuperentityIndex < 2 >( 1 ), 7 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 19 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 19 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 20 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 20 ).template getSuperentityIndex < 2 >( 0 ), 7 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 20 ).template getSuperentityIndex < 2 >( 1 ), 8 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 20 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 20 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 21 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 21 ).template getSuperentityIndex < 2 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 21 ).template getSuperentityIndex < 2 >( 1 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 21 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 21 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 22 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 22 ).template getSuperentityIndex < 2 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 22 ).template getSuperentityIndex < 2 >( 1 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 22 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 22 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 23 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 23 ).template getSuperentityIndex < 2 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 23 ).template getSuperentityIndex < 2 >( 1 ), 10 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 23 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 23 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 24 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 24 ).template getSuperentityIndex < 2 >( 0 ), 9 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 24 ).template getSuperentityIndex < 2 >( 1 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 24 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 24 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 25 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 25 ).template getSuperentityIndex < 2 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 25 ).template getSuperentityIndex < 2 >( 1 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 25 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 25 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 26 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 26 ).template getSuperentityIndex < 2 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 26 ).template getSuperentityIndex < 2 >( 1 ), 11 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 26 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 26 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 27 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 27 ).template getSuperentityIndex < 2 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 27 ).template getSuperentityIndex < 2 >( 1 ), 13 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 27 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 27 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 28 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 28 ).template getSuperentityIndex < 2 >( 0 ), 10 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 28 ).template getSuperentityIndex < 2 >( 1 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 28 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 28 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 29 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 29 ).template getSuperentityIndex < 2 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 29 ).template getSuperentityIndex < 2 >( 1 ), 13 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 29 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 29 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 30 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 30 ).template getSuperentityIndex < 2 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 30 ).template getSuperentityIndex < 2 >( 1 ), 12 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 30 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 30 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 31 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 31 ).template getSuperentityIndex < 2 >( 0 ), 11 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 31 ).template getSuperentityIndex < 2 >( 1 ), 14 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 31 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 31 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 32 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 32 ).template getSuperentityIndex < 2 >( 0 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 32 ).template getSuperentityIndex < 2 >( 1 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 32 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 32 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 33 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 33 ).template getSuperentityIndex < 2 >( 0 ), 13 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 33 ).template getSuperentityIndex < 2 >( 1 ), 14 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 33 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 33 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 1 >( 34 ).template getSuperentitiesCount< 2 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 34 ).template getSuperentityIndex < 2 >( 0 ), 14 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 34 ).template getSuperentityIndex < 2 >( 1 ), 15 ); + ASSERT_EQ( mesh.template getEntity< 1 >( 34 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 1 >( 34 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + + ASSERT_EQ( mesh.template getEntity< 2 >( 0 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 0 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 1 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 1 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 2 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 2 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 3 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 3 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 4 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 4 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 5 ).template getSuperentitiesCount< 3 >( ), 2 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 5 ).template getSuperentityIndex < 3 >( 1 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 6 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 6 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 7 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 7 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 8 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 8 ).template getSuperentityIndex < 3 >( 0 ), 0 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 9 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 9 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 10 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 10 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 11 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 11 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 12 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 12 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 13 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 13 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 14 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 14 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + ASSERT_EQ( mesh.template getEntity< 2 >( 15 ).template getSuperentitiesCount< 3 >( ), 1 ); + EXPECT_EQ( mesh.template getEntity< 2 >( 15 ).template getSuperentityIndex < 3 >( 0 ), 1 ); + + // tests for the dual graph layer + ASSERT_EQ( mesh.getNeighborCounts().getSize(), 2 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 0 ), 1 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 0, 0 ), 1 ); + + ASSERT_EQ( mesh.getCellNeighborsCount( 1 ), 1 ); + EXPECT_EQ( mesh.getCellNeighborIndex ( 1, 0 ), 0 ); + + testFinishedMesh( mesh ); +} + } // namespace MeshTest #endif diff --git a/src/UnitTests/Meshes/MeshTraverserTest.h b/src/UnitTests/Meshes/MeshTraverserTest.h index d0c16bfe45a47d4e64957e637af076302527d22e..af34d1f6f646b0a14be57ef3a4080be912f6456b 100644 --- a/src/UnitTests/Meshes/MeshTraverserTest.h +++ b/src/UnitTests/Meshes/MeshTraverserTest.h @@ -113,8 +113,7 @@ TEST( MeshTest, RegularMeshOfQuadranglesTest ) using TestQuadrangleMesh = Mesh< TestQuadrangleMeshConfig >; Pointers::SharedPointer< TestQuadrangleMesh > meshPointer; MeshBuilder< TestQuadrangleMesh > meshBuilder; - meshBuilder.setPointsCount( numberOfVertices ); - meshBuilder.setCellsCount( numberOfCells ); + meshBuilder.setEntitiesCount( numberOfVertices, numberOfCells ); /**** * Setup vertices @@ -251,8 +250,7 @@ TEST( MeshTest, RegularMeshOfHexahedronsTest ) using TestHexahedronMesh = Mesh< TestHexahedronMeshConfig >; Pointers::SharedPointer< TestHexahedronMesh > meshPointer; MeshBuilder< TestHexahedronMesh > meshBuilder; - meshBuilder.setPointsCount( numberOfVertices ); - meshBuilder.setCellsCount( numberOfCells ); + meshBuilder.setEntitiesCount( numberOfVertices, numberOfCells ); /**** * Setup vertices diff --git a/src/UnitTests/Meshes/VTKReaderTest.cpp b/src/UnitTests/Meshes/VTKReaderTest.cpp index 5bb27c5901c3fd9fec59e6c9bb7aff65126d48ac..9d2df309bb762d2f3c0a26298165d238392f25df 100644 --- a/src/UnitTests/Meshes/VTKReaderTest.cpp +++ b/src/UnitTests/Meshes/VTKReaderTest.cpp @@ -26,6 +26,7 @@ struct GridTag< MyConfigTag, Grid< Dimension, Real, Device, Index > >{ enum { en //template<> struct MeshCellTopologyTag< MyConfigTag, Topologies::Edge > { enum { enabled = true }; }; template<> struct MeshCellTopologyTag< MyConfigTag, Topologies::Triangle > { enum { enabled = true }; }; template<> struct MeshCellTopologyTag< MyConfigTag, Topologies::Tetrahedron > { enum { enabled = true }; }; +template<> struct MeshCellTopologyTag< MyConfigTag, Topologies::Polygon > { enum { enabled = true }; }; } // namespace BuildConfigTags } // namespace Meshes @@ -123,6 +124,24 @@ TEST( VTKReaderTest, triangles_2x2x2_minimized_binary ) test_meshfunction< Readers::VTKReader, Writers::VTKWriter >( mesh, TEST_FILE_NAME, "CellData" ); } +// ASCII data, produced by TNL writer +TEST( VTKReaderTest, polygons ) +{ + using MeshType = Mesh< DefaultConfig< Topologies::Polygon > >; + const MeshType mesh = loadMeshFromFile< MeshType, Readers::VTKReader >( "polygons/unicorn.vtk" ); + + // test that the mesh was actually loaded + const auto vertices = mesh.template getEntitiesCount< 0 >(); + const auto cells = mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); + EXPECT_EQ( vertices, 193 ); + EXPECT_EQ( cells, 90 ); + + test_reader< Readers::VTKReader, Writers::VTKWriter >( mesh, TEST_FILE_NAME ); + test_resolveAndLoadMesh< Writers::VTKWriter, MyConfigTag >( mesh, TEST_FILE_NAME ); + test_meshfunction< Readers::VTKReader, Writers::VTKWriter >( mesh, TEST_FILE_NAME, "PointData" ); + test_meshfunction< Readers::VTKReader, Writers::VTKWriter >( mesh, TEST_FILE_NAME, "CellData" ); +} + // TODO: test case for DataFile version 5.1: triangles_2x2x2/DataFile_version_5.1_exported_from_paraview.vtk #endif diff --git a/src/UnitTests/Meshes/VTUReaderTest.cpp b/src/UnitTests/Meshes/VTUReaderTest.cpp index d3d4391e8e40a7d1bd3e9318543366ba803d11d9..9a37f765db40706dbb3d2dc551555802fa406248 100644 --- a/src/UnitTests/Meshes/VTUReaderTest.cpp +++ b/src/UnitTests/Meshes/VTUReaderTest.cpp @@ -26,6 +26,7 @@ struct GridTag< MyConfigTag, Grid< Dimension, Real, Device, Index > >{ enum { en //template<> struct MeshCellTopologyTag< MyConfigTag, Topologies::Edge > { enum { enabled = true }; }; template<> struct MeshCellTopologyTag< MyConfigTag, Topologies::Triangle > { enum { enabled = true }; }; template<> struct MeshCellTopologyTag< MyConfigTag, Topologies::Tetrahedron > { enum { enabled = true }; }; +template<> struct MeshCellTopologyTag< MyConfigTag, Topologies::Polygon > { enum { enabled = true }; }; } // namespace BuildConfigTags } // namespace Meshes @@ -176,6 +177,24 @@ TEST( VTUReaderTest, triangles_2x2x2_minimized_compressed_paraview ) test_meshfunction< Readers::VTUReader, Writers::VTUWriter >( mesh, TEST_FILE_NAME, "CellData" ); } +// ASCII data, produced by TNL writer +TEST( VTUReaderTest, polygons ) +{ + using MeshType = Mesh< DefaultConfig< Topologies::Polygon > >; + const MeshType mesh = loadMeshFromFile< MeshType, Readers::VTUReader >( "polygons/unicorn.vtu" ); + + // test that the mesh was actually loaded + const auto vertices = mesh.template getEntitiesCount< 0 >(); + const auto cells = mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); + EXPECT_EQ( vertices, 193 ); + EXPECT_EQ( cells, 90 ); + + test_reader< Readers::VTUReader, Writers::VTUWriter >( mesh, TEST_FILE_NAME ); + test_resolveAndLoadMesh< Writers::VTUWriter, MyConfigTag >( mesh, TEST_FILE_NAME ); + test_meshfunction< Readers::VTUReader, Writers::VTUWriter >( mesh, TEST_FILE_NAME, "PointData" ); + test_meshfunction< Readers::VTUReader, Writers::VTUWriter >( mesh, TEST_FILE_NAME, "CellData" ); +} + // TODO: test cases for the appended data block: minimized_appended_binary_compressed.vtu, minimized_appended_binary.vtu, minimized_appended_encoded_compressed.vtu, minimized_appended_encoded.vtu #endif diff --git a/src/UnitTests/Meshes/data/polygons/unicorn.vtk b/src/UnitTests/Meshes/data/polygons/unicorn.vtk new file mode 100644 index 0000000000000000000000000000000000000000..82753c4bcac00a78b6a8acddf945a2fd253a1422 --- /dev/null +++ b/src/UnitTests/Meshes/data/polygons/unicorn.vtk @@ -0,0 +1,384 @@ +# vtk DataFile Version 2.0 +TNL DATA +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 193 float +2.11667 1.01667 0 +2.10954 1.13779 0 +13.9688 14.6094 0 +2.63345 1.45552 0 +1.26887 3.19081 0 +1.43175 3.33333 0 +2.78333 3.33333 0 +2.78333 5.55556 0 +0.836308 5.41737 0 +1.46135 1.37098 0 +1.03292 5.55556 0 +2.88673 3.21582 0 +4.43889 4.77639 0 +2.78676 3.33078 0 +5.5 4.00222 0 +6.9375 4.11262 0 +9.92633 1.33571 0 +7.875 4.3384 0 +4.43889 5.55556 0 +6.09444 5.55556 0 +7.75 4.71184 0 +7.75 5.55556 0 +6.09444 4.98306 0 +4.43889 7.77778 0 +9.40556 4.07056 0 +13.5566 11.0418 0 +2.78333 7.77778 0 +1.21022 7.75699 0 +2.78333 10 0 +1.23873 7.77778 0 +1.14063 9.49448 0 +13.6662 11.1442 0 +2.38265 10.2311 0 +4.44508 10 0 +2.74221 10.0306 0 +6.09444 10 0 +4.61042 10.7729 0 +4.43889 9.99719 0 +3.51321 11.3005 0 +7.75 7.77778 0 +7.75 10 0 +9.40556 7.77778 0 +6.30208 11.0147 0 +10.9112 5.60936 0 +7.49296 12.5661 0 +7.95556 15.3444 0 +8.02781 14.3744 0 +7.82873 12.2222 0 +5.65669 11.1113 0 +7.75 11.8421 0 +14.1641 17.2786 0 +9.40556 10 0 +6.09444 7.77778 0 +9.40556 5.55556 0 +9.74226 1.41409 0 +6.3125 4.53059 0 +10 0.5 0 +10 1.23625 0 +9.59459 3.33333 0 +10.4373 3.33333 0 +10.9243 7.77778 0 +11.1213 10 0 +10.8192 5.55556 0 +10.7976 2.0796 0 +9.40556 12.2222 0 +10.9739 7.74052 0 +5.21718 11.333 0 +4.5 4.60222 0 +13.7827 11.5364 0 +4.42606 10 0 +11.3097 10.125 0 +12.8766 12.2222 0 +12.6906 11.3882 0 +13.7995 12.2222 0 +13.8802 12.2387 0 +14.0757 12.0214 0 +10.7891 12.2222 0 +10.9064 3.56654 0 +14.1196 12.5 0 +8.13556 14.4444 0 +9.40556 14.4444 0 +11.0611 12.4546 0 +11.0611 14.4444 0 +9.14062 16.864 0 +9.40556 16.6667 0 +11.1182 17.836 0 +11.0611 17.6843 0 +3.95347 11.0661 0 +10.2946 18.0757 0 +11.0611 16.6667 0 +9.12947 16.8705 0 +12.7167 14.4444 0 +14.0437 15.8968 0 +13.8492 14.4444 0 +13.8708 18.5401 0 +12.7167 16.5369 0 +14.4058 13.75 0 +12.6586 16.6667 0 +12.7005 18.1691 0 +12.7167 16.7626 0 +14.85 19.85 0 +14.0889 18.85 0 +6.09444 10.3577 0 +14.45 18.85 0 +12.7167 18.1517 0 +12.7167 12.3744 0 +9.42605 3.16901 0 +1.05 1.25 0 +1.65 0.2 0 +1.3 0.4 0 +2.5 0.25 0 +2 0 0 +3.25 1.25 0 +3 0.5 0 +15 13.75 0 +14.75 15 0 +15 14.5 0 +14.25 16 0 +3.75 3 0 +3.5 2 0 +0.35 5.4 0 +0.6 3.05 0 +0.4 4 0 +0.8 2.1 0 +0.35 7.8 0 +0.3 6.8 0 +4.5 4 0 +4 4 0 +5.5 4 0 +6.3125 4 0 +6.9375 4 0 +7.875 4 0 +9.75 0.25 0 +9.25 1.25 0 +9.5 0.5 0 +11.025 2 0 +10.675 1 0 +8.75 3 0 +8.5 4 0 +12.65 11.25 0 +13.5625 11.0125 0 +13.5 11 0 +13.6875 11.0375 0 +0.7 9.65 0 +0.4 8.8 0 +2.15 10.9 0 +1 10.5 0 +13.875 11.075 0 +3.5125 11.3125 0 +3.3 11.3 0 +3.9375 11.3375 0 +4.575 11.375 0 +5.2125 11.4125 0 +6.85 12.65 0 +6.275 11.475 0 +6.7 11.5 0 +5.6375 11.4375 0 +11.35 3.5 0 +11.575 5.5625 0 +11.5 4.5 0 +11.725 7.6875 0 +7.15 14.55 0 +7 13.8 0 +7.65 15.65 0 +7.3 15.3 0 +9 17 0 +14.25 17.25 0 +14 16.5 0 +14.75 18.75 0 +9 2 0 +10.25 0.25 0 +10 0 0 +10.5 0.5 0 +11.2 2.5 0 +11.8 10.125 0 +11.8 8.75 0 +14.25 11.15 0 +11.8 11.5 0 +15 12.5 0 +14.75 11.6 0 +15 12 0 +14.5 11.2 0 +10.25 18.15 0 +10 18 0 +11.15 18.25 0 +10.5 18.3 0 +12.475 18.575 0 +11.8 18.2 0 +13.825 19.325 0 +14.5 19.7 0 +15.1 19.75 0 +15 19.5 0 +15.2 20 0 + + +CELLS 90 567 +6 109 108 0 1 9 107 +4 110 0 108 111 +6 112 3 1 0 110 113 +8 11 13 6 5 4 9 1 3 +5 93 2 92 95 91 +6 116 115 2 93 96 114 +4 117 92 2 115 +5 118 11 3 112 119 +6 122 121 4 5 8 120 +5 107 9 4 121 123 +5 7 10 8 5 6 +5 7 6 13 12 18 +5 26 29 27 10 7 +6 125 120 8 10 27 124 +7 126 67 12 13 11 118 127 +6 18 12 67 14 22 19 +4 128 14 67 126 +5 129 55 22 14 128 +6 55 15 20 21 19 22 +4 130 15 55 129 +5 131 17 20 15 130 +7 132 56 57 16 54 133 134 +5 135 63 16 57 136 +6 59 58 106 54 16 63 +7 137 106 58 24 17 131 138 +5 53 21 20 17 24 +4 18 23 26 7 +4 52 23 18 19 +4 52 19 21 39 +4 21 53 41 39 +5 35 33 37 23 52 +6 59 77 62 53 24 58 +6 72 25 31 68 73 71 +5 141 140 25 72 139 +4 142 31 25 140 +5 37 69 28 26 23 +6 144 124 27 29 30 143 +6 26 28 34 32 30 29 +5 87 38 34 28 69 +5 146 143 30 32 145 +4 147 68 31 142 +6 149 145 32 34 38 148 +6 102 48 66 36 33 35 +7 150 87 69 37 33 36 151 +4 39 40 35 52 +4 151 36 66 152 +4 148 38 87 150 +5 102 35 40 49 42 +4 41 51 40 39 +6 62 43 65 60 41 53 +5 64 47 49 40 51 +7 155 154 42 49 47 44 153 +5 156 48 102 42 154 +6 159 158 43 62 77 157 +4 160 65 43 158 +6 46 44 47 64 80 79 +5 162 153 44 46 161 +6 161 46 79 45 163 164 +6 80 84 83 90 45 79 +4 163 45 90 165 +4 152 66 48 156 +4 99 50 94 104 +8 167 166 50 99 97 95 92 117 +6 168 103 101 94 50 166 +4 60 61 51 41 +5 169 133 54 106 137 +4 171 170 56 132 +5 136 57 56 170 172 +6 157 77 59 63 135 173 +7 174 70 61 60 65 160 175 +5 76 64 51 61 70 +6 176 75 74 73 68 147 +9 139 72 71 105 81 76 70 174 177 +8 105 71 73 74 78 96 93 91 +6 178 78 74 75 179 180 +4 179 75 176 181 +5 82 80 64 76 81 +4 114 96 78 178 +4 89 84 80 82 +4 82 81 105 91 +5 89 86 88 83 84 +6 165 90 83 88 182 183 +6 182 88 86 85 184 185 +7 89 97 99 104 98 85 86 +5 187 184 85 98 186 +5 89 82 91 95 97 +6 186 98 104 94 101 188 +5 188 101 103 100 189 +5 191 190 100 103 168 +3 100 190 192 + + +CELL_TYPES 90 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 diff --git a/src/UnitTests/Meshes/data/polygons/unicorn.vtu b/src/UnitTests/Meshes/data/polygons/unicorn.vtu new file mode 100644 index 0000000000000000000000000000000000000000..51890a98593c1415c8dbfd7b2ad0a97b426e6bfe --- /dev/null +++ b/src/UnitTests/Meshes/data/polygons/unicorn.vtu @@ -0,0 +1,23 @@ + + + + + + +DAkAAAAAAAA=hXcHQD4igj8AAAAAtAIHQBqjkT8AAAAANIBfQRrAaUEAAAAAcoooQHtOuj8AAAAAVWqiPzs2TEAAAAAAlkO3P0dVVUAAAAAAFCIyQEdVVUAAAAAAFCIyQCbHsUAAAAAASBhWPxhbrUAAAAAAhA27P0Z8rz8AAAAAuTaEPybHsUAAAAAAL8A4QP/PTUAAAAAAYwuOQDDYmEAAAAAAR1oyQIArVUAAAAAAAACwQDASgEAAAAAAAADeQJWag0AAAAAAP9IeQYz4qj8AAAAAAAD8QCzUikAAAAAAYwuOQCbHsUAAAAAApwXDQCbHsUAAAAAAAAD4QGXHlkAAAAAAAAD4QCbHsUAAAAAApwXDQDp1n0AAAAAAYwuOQJPj+EAAAAAALH0WQQdCgkAAAAAA1edYQTarMEEAAAAAFCIyQJPj+EAAAAAAfeiaP0M5+EAAAAAAFCIyQAAAIEEAAAAAtI6eP5Pj+EAAAAAAKgCSP2TpF0EAAAAAwahaQaVOMkEAAAAAVn0YQJayI0EAAAAAGD6OQAAAIEEAAAAAXoAvQFZ9IEEAAAAApwXDQAAAIEEAAAAAkIiTQMxdLEEAAAAAYwuOQH70H0EAAAAAb9hgQNnONEEAAAAAAAD4QJPj+EAAAAAAAAD4QAAAIEEAAAAALH0WQZPj+EAAAAAApKrJQDY8MEEAAAAARpQuQeF/s0AAAAAAVMbvQL8OSUEAAAAA85P+QKqCdUEAAAAA6XEAQYv9ZUEAAAAA9YT6QCKOQ0EAAAAAmwO1QOPHMUEAAAAAAAD4QD55PUEAAAAAJ6BiQZM6ikEAAAAALH0WQQAAIEEAAAAApwXDQJPj+EAAAAAALH0WQSbHsUAAAAAATOAbQecAtT8AAAAAAADKQJj6kEAAAAAAAAAgQQAAAD8AAAAAAAAgQXE9nj8AAAAAcYMZQUdVVUAAAAAALv8mQUdVVUAAAAAA78kuQZPj+EAAAAAA2PAxQQAAIEEAAAAAcRstQSbHsUAAAAAA+MIsQSsYBUAAAAAALH0WQSKOQ0EAAAAAGJUvQVey90AAAAAAI/OmQPhTNUEAAAAAAACQQGNFk0AAAAAA8IVcQRiVOEEAAAAASaKNQAAAIEEAAAAAiPQ0QQAAIkEAAAAAjgZOQSKOQ0EAAAAAswxLQRE2NkEAAAAAwcpcQSKOQ0EAAAAATRVeQbfRQ0EAAAAAETZhQahXQEEAAAAAJ6AsQSKOQ0EAAAAAnYAuQTFCZEAAAAAA4ulhQQAASEEAAAAAQSsCQUMcZ0EAAAAALH0WQUMcZ0EAAAAARPowQQtGR0EAAAAARPowQUMcZ0EAAAAA+z8SQXnphkEAAAAALH0WQWdVhUEAAAAAJuQxQSGwjkEAAAAARPowQXJ5jUEAAAAApwV9QL8OMUEAAAAArrYkQQmbkEEAAAAARPowQWdVhUEAAAAATxISQcn2hkEAAAAAmndLQUMcZ0EAAAAA/7JgQUtZfkEAAAAAU5ZdQUMcZ0EAAAAAzO5dQSBSlEEAAAAAmndLQZJLhEEAAAAAKH5mQQAAXEEAAAAAoIlKQWdVhUEAAAAAPzVLQVFakUEAAAAAmndLQc4ZhkEAAAAAmpltQc3MnkEAAAAAImxhQc3MlkEAAAAApwXDQCS5JUEAAAAAMzNnQc3MlkEAAAAAmndLQa42kUEAAAAAmndLQYv9RUEAAAAAGtEWQQ/RSkAAAAAAZmaGPwAAoD8AAAAAMzPTP83MTD4AAAAAZmamP83MzD4AAAAAAAAgQAAAgD4AAAAAAAAAQAAAAAAAAAAAAABQQAAAoD8AAAAAAABAQAAAAD8AAAAAAABwQQAAXEEAAAAAAABsQQAAcEEAAAAAAABwQQAAaEEAAAAAAABkQQAAgEEAAAAAAABwQAAAQEAAAAAAAABgQAAAAEAAAAAAMzOzPs3MrEAAAAAAmpkZPzMzQ0AAAAAAzczMPgAAgEAAAAAAzcxMP2ZmBkAAAAAAMzOzPpqZ+UAAAAAAmpmZPpqZ2UAAAAAAAACQQAAAgEAAAAAAAACAQAAAgEAAAAAAAACwQAAAgEAAAAAAAADKQAAAgEAAAAAAAADeQAAAgEAAAAAAAAD8QAAAgEAAAAAAAAAcQQAAgD4AAAAAAAAUQQAAoD8AAAAAAAAYQQAAAD8AAAAAZmYwQQAAAEAAAAAAzcwqQQAAgD8AAAAAAAAMQQAAQEAAAAAAAAAIQQAAgEAAAAAAZmZKQQAANEEAAAAAAABZQTMzMEEAAAAAAABYQQAAMEEAAAAAAABbQZqZMEEAAAAAMzMzP2ZmGkEAAAAAzczMPs3MDEEAAAAAmpkJQGZmLkEAAAAAAACAPwAAKEEAAAAAAABeQTMzMUEAAAAAzcxgQAAANUEAAAAAMzNTQM3MNEEAAAAAAAB8QGZmNUEAAAAAZmaSQAAANkEAAAAAzcymQJqZNkEAAAAAMzPbQGZmSkEAAAAAzczIQJqZN0EAAAAAZmbWQAAAOEEAAAAAZma0QAAAN0EAAAAAmpk1QQAAYEAAAAAAMzM5QQAAskAAAAAAAAA4QQAAkEAAAAAAmpk7QQAA9kAAAAAAzczkQM3MaEEAAAAAAADgQM3MXEEAAAAAzcz0QGZmekEAAAAAmpnpQM3MdEEAAAAAAAAQQQAAiEEAAAAAAABkQQAAikEAAAAAAABgQQAAhEEAAAAAAABsQQAAlkEAAAAAAAAQQQAAAEAAAAAAAAAkQQAAgD4AAAAAAAAgQQAAAAAAAAAAAAAoQQAAAD8AAAAAMzMzQQAAIEAAAAAAzcw8QQAAIkEAAAAAzcw8QQAADEEAAAAAAABkQWZmMkEAAAAAzcw8QQAAOEEAAAAAAABwQQAASEEAAAAAAABsQZqZOUEAAAAAAABwQQAAQEEAAAAAAABoQTMzM0EAAAAAAAAkQTMzkUEAAAAAAAAgQQAAkEEAAAAAZmYyQQAAkkEAAAAAAAAoQWZmkkEAAAAAmplHQZqZlEEAAAAAzcw8QZqZkUEAAAAAMzNdQZqZmkEAAAAAAABoQZqZnUEAAAAAmplxQQAAnkEAAAAAAABwQQAAnEEAAAAAMzNzQQAAoEEAAAAA + + + + +dAcAAAAAAAA=bQAAAGwAAAAAAAAAAQAAAAkAAABrAAAAbgAAAAAAAABsAAAAbwAAAHAAAAADAAAAAQAAAAAAAABuAAAAcQAAAAsAAAANAAAABgAAAAUAAAAEAAAACQAAAAEAAAADAAAAXQAAAAIAAABcAAAAXwAAAFsAAAB0AAAAcwAAAAIAAABdAAAAYAAAAHIAAAB1AAAAXAAAAAIAAABzAAAAdgAAAAsAAAADAAAAcAAAAHcAAAB6AAAAeQAAAAQAAAAFAAAACAAAAHgAAABrAAAACQAAAAQAAAB5AAAAewAAAAcAAAAKAAAACAAAAAUAAAAGAAAABwAAAAYAAAANAAAADAAAABIAAAAaAAAAHQAAABsAAAAKAAAABwAAAH0AAAB4AAAACAAAAAoAAAAbAAAAfAAAAH4AAABDAAAADAAAAA0AAAALAAAAdgAAAH8AAAASAAAADAAAAEMAAAAOAAAAFgAAABMAAACAAAAADgAAAEMAAAB+AAAAgQAAADcAAAAWAAAADgAAAIAAAAA3AAAADwAAABQAAAAVAAAAEwAAABYAAACCAAAADwAAADcAAACBAAAAgwAAABEAAAAUAAAADwAAAIIAAACEAAAAOAAAADkAAAAQAAAANgAAAIUAAACGAAAAhwAAAD8AAAAQAAAAOQAAAIgAAAA7AAAAOgAAAGoAAAA2AAAAEAAAAD8AAACJAAAAagAAADoAAAAYAAAAEQAAAIMAAACKAAAANQAAABUAAAAUAAAAEQAAABgAAAASAAAAFwAAABoAAAAHAAAANAAAABcAAAASAAAAEwAAADQAAAATAAAAFQAAACcAAAAVAAAANQAAACkAAAAnAAAAIwAAACEAAAAlAAAAFwAAADQAAAA7AAAATQAAAD4AAAA1AAAAGAAAADoAAABIAAAAGQAAAB8AAABEAAAASQAAAEcAAACNAAAAjAAAABkAAABIAAAAiwAAAI4AAAAfAAAAGQAAAIwAAAAlAAAARQAAABwAAAAaAAAAFwAAAJAAAAB8AAAAGwAAAB0AAAAeAAAAjwAAABoAAAAcAAAAIgAAACAAAAAeAAAAHQAAAFcAAAAmAAAAIgAAABwAAABFAAAAkgAAAI8AAAAeAAAAIAAAAJEAAACTAAAARAAAAB8AAACOAAAAlQAAAJEAAAAgAAAAIgAAACYAAACUAAAAZgAAADAAAABCAAAAJAAAACEAAAAjAAAAlgAAAFcAAABFAAAAJQAAACEAAAAkAAAAlwAAACcAAAAoAAAAIwAAADQAAACXAAAAJAAAAEIAAACYAAAAlAAAACYAAABXAAAAlgAAAGYAAAAjAAAAKAAAADEAAAAqAAAAKQAAADMAAAAoAAAAJwAAAD4AAAArAAAAQQAAADwAAAApAAAANQAAAEAAAAAvAAAAMQAAACgAAAAzAAAAmwAAAJoAAAAqAAAAMQAAAC8AAAAsAAAAmQAAAJwAAAAwAAAAZgAAACoAAACaAAAAnwAAAJ4AAAArAAAAPgAAAE0AAACdAAAAoAAAAEEAAAArAAAAngAAAC4AAAAsAAAALwAAAEAAAABQAAAATwAAAKIAAACZAAAALAAAAC4AAAChAAAAoQAAAC4AAABPAAAALQAAAKMAAACkAAAAUAAAAFQAAABTAAAAWgAAAC0AAABPAAAAowAAAC0AAABaAAAApQAAAJgAAABCAAAAMAAAAJwAAABjAAAAMgAAAF4AAABoAAAApwAAAKYAAAAyAAAAYwAAAGEAAABfAAAAXAAAAHUAAACoAAAAZwAAAGUAAABeAAAAMgAAAKYAAAA8AAAAPQAAADMAAAApAAAAqQAAAIUAAAA2AAAAagAAAIkAAACrAAAAqgAAADgAAACEAAAAiAAAADkAAAA4AAAAqgAAAKwAAACdAAAATQAAADsAAAA/AAAAhwAAAK0AAACuAAAARgAAAD0AAAA8AAAAQQAAAKAAAACvAAAATAAAAEAAAAAzAAAAPQAAAEYAAACwAAAASwAAAEoAAABJAAAARAAAAJMAAACLAAAASAAAAEcAAABpAAAAUQAAAEwAAABGAAAArgAAALEAAABpAAAARwAAAEkAAABKAAAATgAAAGAAAABdAAAAWwAAALIAAABOAAAASgAAAEsAAACzAAAAtAAAALMAAABLAAAAsAAAALUAAABSAAAAUAAAAEAAAABMAAAAUQAAAHIAAABgAAAATgAAALIAAABZAAAAVAAAAFAAAABSAAAAUgAAAFEAAABpAAAAWwAAAFkAAABWAAAAWAAAAFMAAABUAAAApQAAAFoAAABTAAAAWAAAALYAAAC3AAAAtgAAAFgAAABWAAAAVQAAALgAAAC5AAAAWQAAAGEAAABjAAAAaAAAAGIAAABVAAAAVgAAALsAAAC4AAAAVQAAAGIAAAC6AAAAWQAAAFIAAABbAAAAXwAAAGEAAAC6AAAAYgAAAGgAAABeAAAAZQAAALwAAAC8AAAAZQAAAGcAAABkAAAAvQAAAL8AAAC+AAAAZAAAAGcAAACoAAAAZAAAAL4AAADAAAAA + + +aAEAAAAAAAA=BgAAAAoAAAAQAAAAGAAAAB0AAAAjAAAAJwAAACwAAAAyAAAANwAAADwAAABBAAAARgAAAEwAAABTAAAAWQAAAF0AAABiAAAAaAAAAGwAAABxAAAAeAAAAH0AAACDAAAAigAAAI8AAACTAAAAlwAAAJsAAACfAAAApAAAAKoAAACwAAAAtQAAALkAAAC+AAAAxAAAAMoAAADPAAAA1AAAANgAAADeAAAA5AAAAOsAAADvAAAA8wAAAPcAAAD8AAAAAAEAAAYBAAALAQAAEgEAABcBAAAdAQAAIQEAACcBAAAsAQAAMgEAADgBAAA8AQAAQAEAAEQBAABMAQAAUgEAAFYBAABbAQAAXwEAAGQBAABqAQAAcQEAAHYBAAB8AQAAhQEAAI0BAACTAQAAlwEAAJwBAACgAQAApAEAAKgBAACtAQAAswEAALkBAADAAQAAxQEAAMoBAADQAQAA1QEAANoBAADdAQAA + + +WgAAAAAAAAA=BwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcH + + + + + diff --git a/src/UnitTests/Meshes/data/polyhedrons/cube1m_1.fpma b/src/UnitTests/Meshes/data/polyhedrons/cube1m_1.fpma new file mode 100644 index 0000000000000000000000000000000000000000..d53e228dfae26d54dc1e696de04f7b1802b06688 --- /dev/null +++ b/src/UnitTests/Meshes/data/polyhedrons/cube1m_1.fpma @@ -0,0 +1,5455 @@ +2358 + 0.1666666667 1 0 + 0 0 0.1666666667 + 0 0 0 + 0 0 1 + 0 0 0.8333333333 + 1 1 0.1666666667 + 0 0 0.3333333333 + 0 0 0.6666666667 + 0 1 0 + 0 0.1666666667 0 + 1 1 0.3333333333 + 0 0.3333333333 0 + 0.3333333333 1 0 + 0 0.5 0 + 0 0.6666666667 0 + 1 1 0.5 + 1 0.1666666667 0 + 0 0.1666666667 1 + 1 1 0.8333333333 + 0 1 1 + 1 1 0.6666666667 + 1 0.3333333333 0 + 0 0 0.5 + 0 0.8333333333 0 + 0.5 1 0 + 0 1 0.3333333333 + 1 0.5 0 + 0 1 0.1666666667 + 0.6666666667 1 0 + 0 1 0.8333333333 + 0 1 0.5 + 1 0.6666666667 0 + 0 1 0.6666666667 + 0 0.8333333333 1 + 1 0.8333333333 0 + 0 0.3333333333 1 + 0 0.5 1 + 0.8333333333 1 0 + 0 0.6666666667 1 + 1 1 0 + 0.1666666667 1 1 + 1 0.1666666667 1 + 0.1666666667 0 0 + 0.1666666667 0 1 + 0.5 0 0 + 0.3333333333 1 1 + 0.3333333333 0 0 + 0.3333333333 0 1 + 1 0.3333333333 1 + 0.5 0 1 + 0.6666666667 0 1 + 0.5 1 1 + 1 0 1 + 1 0.5 1 + 0.6666666667 0 0 + 0.8333333333 0 0 + 0.6666666667 1 1 + 1 0 0.1666666667 + 1 0 0 + 1 0.6666666667 1 + 1 0 0.3333333333 + 1 0.8333333333 1 + 0.8333333333 1 1 + 1 1 1 + 1 0 0.5 + 1 0 0.8333333333 + 1 0 0.6666666667 + 0.8333333333 0 1 + 0.02083333333 0.04166666667 0.9375 + 0.09635416667 0.02083333333 0.9609375 + 0.0546875 0.02083333333 0.9192708333 + 0.01692708333 0.02864583333 0.75390625 + 0.01692708333 0.02604166667 0.25390625 + 0.01692708333 0.046875 0.19140625 + 0.05078125 0.02083333333 0.1627604167 + 0.03385416667 0.02083333333 0.1015625 + 0.02083333333 0.08333333333 0.02083333333 + 0.0546875 0.04166666667 0.05989583333 + 0.09635416667 0.02083333333 0.0390625 + 0.01953125 0.2560763917 0.02604166667 + 0.1640625 0.046875 0.0390625 + 0.2109375 0.02604166667 0.07552083333 + 0.2604166667 0.02604166667 0.03645833333 + 0.02083333333 0.08333333333 0.9791666667 + 0.054049525 0.06971675833 0.9071366667 + 0.03321619167 0.1478417583 0.912345 + 0.03321619167 0.07752925833 0.8472408333 + 0.054049525 0.111383425 0.9488033333 + 0.08790369167 0.048883425 0.8889075 + 0.03321619167 0.134820925 0.8524491667 + 0.050143275 0.056695925 0.80687625 + 0.0505773 0.189508425 0.9331783333 + 0.08399744167 0.02805009167 0.8277095833 + 0.07141063333 0.1530500917 0.9696366667 + 0.1295703583 0.048883425 0.9305741667 + 0.1764453583 0.02805009167 0.8941158333 + 0.2560763917 0.01953125 0.9635416667 + 0.15908425 0.068414675 0.9696366667 + 0.20595925 0.04758134167 0.9331783333 + 0.1234939667 0.1634667583 0.9696366667 + 0.1695009167 0.1204980083 0.9696366667 + 0.04296875 0.02604166667 0.3111979167 + 0.02604166667 0.05989583333 0.6536458333 + 0.04296875 0.02864583333 0.6966145833 + 0.02604166667 0.05729166667 0.3541666667 + 0.02604166667 0.03125 0.5885416667 + 0.02604166667 0.03125 0.4114583333 + 0.136080775 0.02805009167 0.7964595833 + 0.186862025 0.02805009167 0.8211991667 + 0.03084818333 0.1736490417 0.6904780833 + 0.08099145833 0.09753246667 0.7760001667 + 0.03084818333 0.1996907083 0.7581864167 + 0.064064375 0.1548241333 0.80073975 + 0.1330747917 0.06888663333 0.7629793333 + 0.05688985 0.100732375 0.6644364167 + 0.07381693333 0.069482375 0.7074051667 + 0.1259002667 0.04083654167 0.6943843333 + 0.02083333333 0.9166666667 0.02083333333 + 0.02083333333 0.9791666667 0.08333333333 + 0.04166666667 0.9583333333 0.04166666667 + 0.08333333333 0.9791666667 0.02083333333 + 0.74609375 0.01692708333 0.02604166667 + 0.58246525 0.02604166667 0.02256944167 + 0.04254963333 0.1314113667 0.049558875 + 0.07249755 0.06891136667 0.1498192917 + 0.0217163 0.1782863667 0.07560054167 + 0.03864338333 0.09495303333 0.178465125 + 0.04124755 0.2208210917 0.05476720833 + 0.06208088333 0.1739460917 0.02872554167 + 0.0764038 0.0897447 0.088621375 + 0.08031005 0.2642238417 0.05476720833 + 0.05859375 0.2994791417 0.02604166667 + 0.0390625 0.3229166667 0.07118055833 + 0.0607788 0.2876613667 0.0999061 + 0.0217163 0.2546752833 0.1519894333 + 0.0217163 0.1470363667 0.1693505417 + 0.0217163 0.1887030333 0.127683875 + 0.02522786667 0.1894292 0.3373825917 + 0.02522786667 0.2849152833 0.389465925 + 0.02522786667 0.2258875333 0.3946742583 + 0.05126953333 0.115644475 0.36588375 + 0.029296875 0.4399595 0.03125 + 0.0390625 0.3697916667 0.07638889167 + 0.068359375 0.4000289167 0.03125 + 0.02864583333 0.7447916667 0.01822916667 + 0.5303819167 0.05729166667 0.02256944167 + 0.4939235833 0.03125 0.05381944167 + 0.4375 0.03125 0.03125 + 0.1238965083 0.083826275 0.1897731083 + 0.09436770833 0.06178990833 0.2886517333 + 0.1542635417 0.03574824167 0.2339642333 + 0.2979267083 0.03574824167 0.29516215 + 0.1464510417 0.03574824167 0.2938600667 + 0.2050447917 0.03574824167 0.20922465 + 0.2206697917 0.06178990833 0.1363079833 + 0.09004234167 0.1098679417 0.2184189417 + 0.2753572917 0.03574824167 0.23266215 + 0.07311525833 0.161951275 0.2093043583 + 0.1026684917 0.1201427167 0.3225042333 + 0.05139895833 0.1876579667 0.2510359917 + 0.076626825 0.1939274417 0.294003075 + 0.3834961667 0.03554730833 0.1632702667 + 0.3626628333 0.03554730833 0.1007702667 + 0.2838534583 0.09733721667 0.1303074167 + 0.4095378333 0.06679730833 0.06431193333 + 0.3157878333 0.061588975 0.06952026667 + 0.3203117917 0.07129555 0.1928074167 + 0.2050447917 0.1138732417 0.09984965 + 0.1744791667 0.09895833333 0.0390625 + 0.1323933833 0.2485988417 0.02872554167 + 0.1590527583 0.1359096083 0.1285751917 + 0.1141642167 0.1843627583 0.02872554167 + 0.2682284583 0.14942055 0.09384908333 + 0.1284871333 0.1209947 0.06778804167 + 0.3817600833 0.1119362 0.03306193333 + 0.3036350833 0.1588112 0.03306193333 + 0.3348850833 0.1067278667 0.03306193333 + 0.05989583333 0.6822916667 0.01822916667 + 0.03125 0.5364583333 0.06770833333 + 0.060546875 0.5024595 0.03125 + 0.03125 0.6432291667 0.0546875 + 0.03125 0.5885416667 0.03645833333 + 0.4025934167 0.1744362 0.03306193333 + 0.4270833333 0.03125 0.96875 + 0.4665798333 0.03125 0.9405381667 + 0.01736110833 0.2447916667 0.9635416667 + 0.02083333333 0.953125 0.8489583333 + 0.02083333333 0.9791666667 0.9166666667 + 0.02083333333 0.9166666667 0.9791666667 + 0.04166666667 0.9583333333 0.9583333333 + 0.08333333333 0.9791666667 0.9791666667 + 0.01736110833 0.3020833333 0.9270833333 + 0.05208333333 0.328125 0.9635416667 + 0.07534205833 0.2464700083 0.7782895833 + 0.1486605417 0.2733418 0.9602073333 + 0.095071175 0.2232668917 0.8933856667 + 0.10855825 0.2016034333 0.8208429167 + 0.1471545083 0.2180585583 0.929844 + 0.09657720833 0.3202168 0.923749 + 0.044493875 0.35493905 0.7883323333 + 0.044493875 0.3045918 0.814374 + 0.06185498333 0.2941751333 0.8872906667 + 0.1814700583 0.1805001667 0.8025325833 + 0.2259196667 0.06423849167 0.805493 + 0.3385368083 0.0361884 0.815023 + 0.1890595167 0.1050750333 0.7694085833 + 0.2968701417 0.0361884 0.7733563333 + 0.3194395583 0.0752509 0.877523 + 0.2148628167 0.1946210583 0.929844 + 0.38715275 0.0703125 0.96875 + 0.3298610833 0.0390625 0.9322916667 + 0.2994791417 0.05859375 0.9635416667 + 0.2356912917 0.178726125 0.8750753333 + 0.249362 0.08664384167 0.9331783333 + 0.233737 0.138727175 0.9696366667 + 0.25890575 0.1033009917 0.8784096667 + 0.2181050167 0.2889668 0.9602073333 + 0.2684522083 0.2446959667 0.9602073333 + 0.02694330833 0.2504563333 0.6035838333 + 0.05779149167 0.228792875 0.6560410833 + 0.1022853667 0.2729680083 0.7204150833 + 0.02694330833 0.31208825 0.6044519167 + 0.02694330833 0.3572271667 0.6669519167 + 0.07143718333 0.3397703833 0.7304578333 + 0.02694330833 0.40786375 0.6452505 + 0.02694330833 0.4252248333 0.5827505 + 0.2553168083 0.0429209 0.4165185833 + 0.1082472167 0.1987971083 0.5986013333 + 0.050455725 0.1679209 0.4946435833 + 0.1025390583 0.0429209 0.4946435833 + 0.07568359167 0.1950237083 0.4438606667 + 0.1531242167 0.13702195 0.3744394833 + 0.107345575 0.1150074417 0.5939758333 + 0.07649739167 0.0741709 0.4477685833 + 0.20629905 0.1199458417 0.6694155 + 0.1017252583 0.1325237083 0.417819 + 0.1650390583 0.0429209 0.4946435833 + 0.191080725 0.0429209 0.4165185833 + 0.1594289083 0.08375744167 0.6252258333 + 0.2442157667 0.07866914167 0.3523057333 + 0.050455725 0.1054209 0.4946435833 + 0.07649739167 0.0741709 0.5415185833 + 0.1799796833 0.07866914167 0.3523057333 + 0.191080725 0.0429209 0.5727685833 + 0.07739903333 0.2204605667 0.5461440833 + 0.5238715 0.05729166667 0.9717881667 + 0.7565104167 0.01692708333 0.9635416667 + 0.69921875 0.04296875 0.9635416667 + 0.59375 0.02604166667 0.9635416667 + 0.5499131667 0.02604166667 0.9353298333 + 0.6614583333 0.02604166667 0.9270833333 + 0.8984375 0.03385416667 0.9791666667 + 0.3482014583 0.06983095833 0.3302593167 + 0.4391635833 0.03408271667 0.3597499167 + 0.3549615417 0.1053782667 0.2643629167 + 0.3454135833 0.03408271667 0.4830138333 + 0.3055915583 0.07700361667 0.45161575 + 0.2944905167 0.1127518583 0.3874029 + 0.3086545583 0.106713675 0.5041663333 + 0.3484765833 0.063792775 0.5355644167 + 0.3225025583 0.06589845833 0.7113235833 + 0.3398685 0.02971005833 0.6671339167 + 0.2583798083 0.07263095833 0.5732358333 + 0.2687916167 0.1088193583 0.6434671667 + 0.2982018333 0.02971005833 0.6046339167 + 0.4599969167 0.03408271667 0.4222499167 + 0.4079135833 0.03408271667 0.4830138333 + 0.4109765833 0.063792775 0.5355644167 + 0.42939875 0.02971005833 0.5767838333 + 0.4085654167 0.02971005833 0.6392838333 + 0.1748782667 0.2758540833 0.7064455833 + 0.2208467667 0.2282528167 0.74600975 + 0.1808401167 0.24334985 0.6158818333 + 0.2268086167 0.1957485833 0.655446 + 0.2893011833 0.1846221 0.6294976667 + 0.9791666667 0.02083333333 0.9166666667 + 0.9401041667 0.0546875 0.9583333333 + 0.9609375 0.09635416667 0.9791666667 + 0.9739583333 0.02604166667 0.2604166667 + 0.5297511667 0.05973006667 0.083532425 + 0.5590480833 0.1382167583 0.02971298333 + 0.6887500833 0.02848006667 0.1978264083 + 0.6373900833 0.02848006667 0.1234629833 + 0.667338 0.07144881667 0.02971298333 + 0.5662095 0.08577173333 0.052282425 + 0.6495428333 0.02848006667 0.07832409167 + 0.4870320833 0.095277375 0.09402491667 + 0.6955498333 0.02848006667 0.152976875 + 0.56968175 0.02848006667 0.1286713167 + 0.698588 0.04540715 0.05575465 + 0.6182928333 0.05452173333 0.052282425 + 0.7534315 0.05064915 0.140494025 + 0.86343725 0.02216908333 0.1732810417 + 0.8217705833 0.02216908333 0.131614375 + 0.7918226667 0.03909616667 0.05869770833 + 0.83218725 0.02216908333 0.07953104167 + 0.9155205833 0.02216908333 0.162864375 + 0.7443169167 0.06757623333 0.08841069167 + 0.9363539167 0.04821075 0.209739375 + 0.8984375 0.03385416667 0.02083333333 + 0.8608330833 0.05602325 0.053489375 + 0.8204685 0.07295033333 0.03265604167 + 0.94156225 0.04300241667 0.115989375 + 0.90249975 0.07685658333 0.07432270833 + 0.9791666667 0.02083333333 0.08333333333 + 0.9401041667 0.0546875 0.04166666667 + 0.9623955833 0.06904408333 0.162864375 + 0.9609375 0.09635416667 0.02083333333 + 0.9427083333 0.02604166667 0.3125 + 0.96875 0.05729166667 0.3385416667 + 0.96875 0.03125 0.3958333333 + 0.9623955833 0.1211274167 0.1732810417 + 0.03093301667 0.3364370833 0.47862 + 0.10833205 0.2799879833 0.508271 + 0.18092495 0.293290725 0.5463848333 + 0.05616088333 0.301907975 0.426969 + 0.057876325 0.392449 0.5353288333 + 0.03093301667 0.3989370833 0.47862 + 0.057876325 0.329949 0.5353288333 + 0.1066166083 0.254551125 0.44765425 + 0.05616088333 0.3131927 0.372426175 + 0.03093301667 0.3590065583 0.3398757583 + 0.03093301667 0.4268354167 0.4326853333 + 0.03093301667 0.4060020833 0.3701853333 + 0.02083333333 0.9427083333 0.140625 + 0.0300773 0.7652164167 0.1853577333 + 0.0613273 0.6714664167 0.09160773333 + 0.08997313333 0.7105289167 0.0551494 + 0.05091063333 0.88761225 0.1358785667 + 0.0300773 0.81729975 0.1332744 + 0.05872313333 0.7730289167 0.0551494 + 0.0300773 0.7027164167 0.1645244 + 0.0300773 0.8120914167 0.07598273333 + 0.05091063333 0.8615705833 0.05775356667 + 0.07955646667 0.8225080833 0.03692023333 + 0.07174396667 0.90323725 0.0785869 + 0.140625 0.9427083333 0.02083333333 + 0.1368481333 0.8277164167 0.03692023333 + 0.1290356333 0.88761225 0.05775356667 + 0.03645833333 0.96875 0.4114583333 + 0.03645833333 0.9322916667 0.34375 + 0.08736896667 0.9084455833 0.1723369 + 0.03645833333 0.9635416667 0.2395833333 + 0.07291666667 0.9635416667 0.296875 + 0.05729166667 0.9635416667 0.1770833333 + 0.1029939667 0.9084455833 0.2504619 + 0.1446606333 0.9084455833 0.1150452333 + 0.1901041667 0.9635416667 0.0390625 + 0.2526041667 0.9635416667 0.01822916667 + 0.1848958333 0.9635416667 0.09635416667 + 0.3098958333 0.9270833333 0.01822916667 + 0.3515625 0.9635416667 0.0546875 + 0.7892185 0.1250336667 0.03265604167 + 0.6777546667 0.12353215 0.02971298333 + 0.7391085833 0.1196595667 0.062369025 + 0.6215480833 0.1590500917 0.02971298333 + 0.9635416667 0.2560763917 0.01953125 + 0.214410775 0.3202254167 0.04452405 + 0.1703385333 0.2321766917 0.1340367417 + 0.1059187417 0.3162201167 0.1183884833 + 0.101300825 0.3191820333 0.3179918917 + 0.1134993167 0.4129626667 0.07577405 + 0.1217667667 0.2641528583 0.2708187917 + 0.08420244167 0.3827254167 0.1209129417 + 0.2248274417 0.3931420833 0.04452405 + 0.0965389 0.2578833833 0.2278517083 + 0.1056868167 0.4737265833 0.07577405 + 0.04513994167 0.4573781667 0.20077405 + 0.04513994167 0.3610240583 0.2226201167 + 0.1759993167 0.4233793333 0.04452405 + 0.1681868167 0.48414325 0.04452405 + 0.04513994167 0.4018226667 0.1834129417 + 0.07607295833 0.3649958917 0.285441475 + 0.04513994167 0.308940725 0.21220345 + 0.158002075 0.2814978667 0.07324959167 + 0.1182552 0.2321766917 0.186120075 + 0.06685624167 0.2832340333 0.1704718167 + 0.1991081083 0.2629204 0.27948425 + 0.18395795 0.2646033917 0.4017768833 + 0.2044238917 0.2095742167 0.3546037833 + 0.3281362167 0.1779305333 0.28098555 + 0.1786421667 0.317949575 0.32665735 + 0.2815541083 0.185304125 0.3675672 + 0.08008248333 0.563195 0.1072125167 + 0.1101597833 0.6435155833 0.11288275 + 0.04883248333 0.55972275 0.1697125167 + 0.04883248333 0.62222275 0.2113791833 + 0.07890978333 0.6747655833 0.1857994167 + 0.093972425 0.5049481667 0.1777782333 + 0.125222425 0.5084204167 0.1152782333 + 0.187722425 0.5188370833 0.08402823333 + 0.1889314667 0.7756330833 0.03692023333 + 0.18307645 0.66955725 0.07642441667 + 0.1628898 0.70792475 0.03692023333 + 0.4476623333 0.080713125 0.1904869083 + 0.5617993333 0.07364588333 0.16977685 + 0.6042414167 0.04516581667 0.2699828167 + 0.5051384167 0.04516581667 0.2025638667 + 0.5329161667 0.04516581667 0.2615916167 + 0.4807603333 0.07924853333 0.3244665583 + 0.4354370833 0.1147958417 0.2672507417 + 0.4086117583 0.1873481083 0.283873375 + 0.6227079167 0.07364588333 0.20941805 + 0.50432325 0.1091931917 0.1576998917 + 0.5506575 0.1757745917 0.06124940833 + 0.6131575 0.196607925 0.06124940833 + 0.4939965833 0.209794525 0.031536425 + 0.4584389167 0.1928968083 0.06459835833 + 0.5150998333 0.158876875 0.09431134167 + 0.532391 0.1727926917 0.1579863167 + 0.3819363333 0.2166494583 0.06143280833 + 0.3630235 0.2679077333 0.028370875 + 0.2425484833 0.2575619167 0.133682075 + 0.4377818333 0.2351100667 0.09296923333 + 0.2678064917 0.27803085 0.2128047083 + 0.329853 0.2062327917 0.06143280833 + 0.269274525 0.3086192583 0.072894925 + 0.3109401667 0.2574910667 0.028370875 + 0.294446375 0.1968421417 0.1222199583 + 0.400179925 0.22672865 0.2042304167 + 0.3197043833 0.217311075 0.2013425917 + 0.4654896667 0.2177758833 0.1566442083 + 0.2476182583 0.491638 0.08402823333 + 0.276910775 0.4267069167 0.04452405 + 0.308337025 0.375170175 0.072894925 + 0.2378515667 0.6282268333 0.03950418333 + 0.2274349 0.5761435 0.03950418333 + 0.2873307333 0.5489444167 0.03950418333 + 0.3955755833 0.314927425 0.028370875 + 0.4601016667 0.2917213417 0.0599073 + 0.38255475 0.371061675 0.028370875 + 0.4987709167 0.2707031083 0.031536425 + 0.5955590833 0.252329275 0.031536425 + 0.5378334167 0.292404525 0.031536425 + 0.40625 0.9635416667 0.03645833333 + 0.9322916667 0.3298610833 0.0390625 + 0.9635416667 0.2994791417 0.05859375 + 0.01822916667 0.9739583333 0.7369791667 + 0.0390625 0.9739583333 0.7994791667 + 0.03645833333 0.9375 0.5260416667 + 0.03645833333 0.96875 0.5885416667 + 0.07291666667 0.96875 0.4791666667 + 0.03372329167 0.7967290833 0.6140181667 + 0.070181625 0.9359073333 0.6300771667 + 0.03372329167 0.8331874167 0.6713098333 + 0.08841079167 0.9671573333 0.6639313333 + 0.05195245833 0.9411156667 0.6951813333 + 0.03372329167 0.9098656667 0.6613271667 + 0.48840175 0.04841971667 0.7180854167 + 0.4626735833 0.07966971667 0.8843903333 + 0.391512975 0.114318175 0.7280924167 + 0.372824975 0.1236706167 0.8578335 + 0.4249131667 0.1187322167 0.9126021667 + 0.3599392083 0.1901209167 0.70370625 + 0.4393814167 0.078129775 0.6820943333 + 0.44184025 0.04841971667 0.8218903333 + 0.5460069167 0.07446138333 0.879182 + 0.4904513333 0.04841971667 0.7906403333 + 0.51996525 0.1057113833 0.9156403333 + 0.5373263333 0.04841971667 0.816682 + 0.53383 0.04841971667 0.6877035 + 0.391922225 0.08460811667 0.7953335 + 0.5221354167 0.1682113833 0.9438521667 + 0.4561631667 0.1812322167 0.9438521667 + 0.05989583333 0.8596176667 0.941248 + 0.09101495833 0.8840666667 0.740596 + 0.0390625 0.78814775 0.768939 + 0.07278579167 0.8073884167 0.7375578333 + 0.0390625 0.7048144167 0.831439 + 0.08072916667 0.9012843333 0.9204146667 + 0.0390625 0.7464810833 0.8106056667 + 0.05989583333 0.896076 0.8527063333 + 0.0390625 0.8439926667 0.8214563333 + 0.0390625 0.8127426667 0.9152063333 + 0.0390625 0.6683560833 0.7949806667 + 0.0390625 0.802326 0.863123 + 0.078125 0.9169093333 0.8032271667 + 0.05729166667 0.7632635 0.9360396667 + 0.05729166667 0.7111801667 0.9047896667 + 0.01822916667 0.7369791667 0.9739583333 + 0.01822916667 0.6848958333 0.9427083333 + 0.078125 0.8101385 0.9620813333 + 0.03125 0.421875 0.9635416667 + 0.1104661 0.3723001333 0.923749 + 0.03125 0.4657118333 0.9353298333 + 0.065972225 0.3802083333 0.9635416667 + 0.06770833333 0.5177951667 0.9717881667 + 0.03645833333 0.5989583333 0.96875 + 0.03645833333 0.5594618333 0.9405381667 + 0.09375 0.6799301667 0.9308313333 + 0.0546875 0.6536458333 0.96875 + 0.1729661 0.3775084667 0.9602073333 + 0.2285216833 0.3410501333 0.9602073333 + 0.1354166667 0.942951 0.8344771667 + 0.148306625 0.9101083333 0.771846 + 0.1744791667 0.9064926667 0.9047896667 + 0.1770833333 0.9635416667 0.9427083333 + 0.1380208333 0.8856593333 0.941248 + 0.1354166667 0.8153468333 0.9620813333 + 0.140625 0.9427083333 0.9791666667 + 0.2395833333 0.9635416667 0.9635416667 + 0.9405381667 0.038628475 0.4609375 + 0.96875 0.069878475 0.4318576667 + 0.9453125 0.03645833333 0.6484375 + 0.9353298333 0.03645833333 0.5499131667 + 0.9635416667 0.03645833333 0.59375 + 0.9717881667 0.07508680833 0.5182291667 + 0.9817708333 0.07291666667 0.6901041667 + 0.9791666667 0.05729166667 0.859375 + 0.9609375 0.03645833333 0.8098958333 + 0.9817708333 0.03645833333 0.7473958333 + 0.03967946667 0.55394775 0.8195460833 + 0.03967946667 0.4584616667 0.81433775 + 0.07874196667 0.6197285833 0.80983925 + 0.03967946667 0.5053366667 0.7882960833 + 0.03967946667 0.50171975 0.7218898333 + 0.07092946667 0.4654060833 0.87683775 + 0.18370955 0.3597117917 0.72049625 + 0.1154233417 0.41366105 0.8652569167 + 0.1779233417 0.4188693833 0.90171525 + 0.08417334167 0.4067166333 0.8027569167 + 0.066622775 0.4396760833 0.690057 + 0.11111665 0.3915479667 0.7448824167 + 0.3053752083 0.2861834667 0.9177309167 + 0.3858813333 0.2732583333 0.9575235833 + 0.4201695 0.24355305 0.90137575 + 0.2828057917 0.3512876333 0.9177309167 + 0.235679675 0.3978568833 0.8592388333 + 0.4194461667 0.3253416667 0.9575235833 + 0.245772575 0.3694929583 0.7723526667 + 0.3680813083 0.21724145 0.8466070833 + 0.2914814333 0.2442468667 0.86296225 + 0.2790049167 0.2809871083 0.7760760833 + 0.3556047917 0.2539816917 0.7597209167 + 0.3969008333 0.3791610833 0.9575235833 + 0.3407665833 0.3921819167 0.9575235833 + 0.04354174167 0.5240901667 0.4837361667 + 0.04354174167 0.55770325 0.6294248333 + 0.07048505 0.4609373333 0.5715503333 + 0.1101645167 0.4606315833 0.63805825 + 0.04354174167 0.5615854167 0.564393 + 0.08322120833 0.52267525 0.6698910833 + 0.07447475833 0.4651520833 0.46922825 + 0.04354174167 0.5268631667 0.5383513333 + 0.1014180667 0.4281615 0.5241286667 + 0.1827574167 0.412881075 0.6457901667 + 0.1740109667 0.3789642417 0.5622425 + 0.3193575417 0.2300885583 0.550346 + 0.4145420917 0.2334556583 0.3668911083 + 0.250035825 0.3768294333 0.522655 + 0.349122725 0.1883685333 0.495246 + 0.3331233167 0.2312107417 0.4228597167 + 0.26169825 0.2879054417 0.4228061333 + 0.2569498083 0.2911559167 0.5067973333 + 0.6109795 0.07973439167 0.3379210917 + 0.49845275 0.1954719667 0.4008456417 + 0.6525714167 0.034568575 0.4267345833 + 0.666605 0.034568575 0.3784127833 + 0.65980525 0.034568575 0.5317693333 + 0.6977103333 0.034568575 0.4788179167 + 0.5378456667 0.1138171083 0.375043725 + 0.59730525 0.034568575 0.51440825 + 0.5900714167 0.034568575 0.4475679167 + 0.5309711667 0.06865129167 0.43636875 + 0.9217485 0.131804025 0.9480160833 + 0.7876339167 0.1383144417 0.9688494167 + 0.8592485 0.069304025 0.9480160833 + 0.8188839167 0.08623110833 0.9688494167 + 0.8410193333 0.03544985833 0.91155775 + 0.9217485 0.07190819167 0.8204119167 + 0.80065475 0.05237694167 0.9323910833 + 0.8644568333 0.03544985833 0.84124525 + 0.8123735 0.03544985833 0.7891619167 + 0.9009151667 0.09013735833 0.92718275 + 0.9399776667 0.092741525 0.8698910833 + 0.7277380833 0.1305019417 0.9688494167 + 0.7433630833 0.07841860833 0.9323910833 + 0.7184708333 0.1162253167 0.8863444167 + 0.56104525 0.191695175 0.8978055 + 0.6847431667 0.05473379167 0.80812 + 0.6343959167 0.05473379167 0.7820783333 + 0.7445125 0.09018365 0.81342775 + 0.6329491667 0.05473379167 0.72565475 + 0.5769595833 0.1031535083 0.7424235833 + 0.6170348333 0.1953587917 0.9539533333 + 0.5784063333 0.1031535083 0.7988471667 + 0.5870869167 0.129195175 0.8613471667 + 0.7028458333 0.16830865 0.92280275 + 0.6587015 0.08077545833 0.8810366667 + 0.8852901667 0.178679025 0.9688494167 + 0.7653458333 0.2099753167 0.92280275 + 0.8123735 0.1890956917 0.9688494167 + 0.5323628333 0.06169471667 0.5868518333 + 0.5715861667 0.164848225 0.7104240833 + 0.52559775 0.1303460083 0.5015915 + 0.5284565833 0.1101144333 0.655704 + 0.4761086667 0.091404775 0.5812426667 + 0.4576865 0.1254874917 0.54002325 + 0.4240150667 0.2156272333 0.6639754167 + 0.4058894833 0.248862375 0.5862029167 + 0.5728345833 0.09626329167 0.55069575 + 0.5035659167 0.2120008667 0.4926711667 + 0.4722024167 0.1398244917 0.6500948333 + 0.4356546667 0.20714235 0.5311029167 + 0.3822529 0.324984625 0.7335258333 + 0.3008386167 0.4012591583 0.7311815833 + 0.4302342333 0.2931085083 0.68150275 + 0.41210865 0.32634365 0.60373025 + 0.255374025 0.4362827417 0.65915925 + 0.318662725 0.39324335 0.583731 + 0.960811 0.163054025 0.87249525 + 0.960811 0.1682623583 0.9297869167 + 0.9243526667 0.2151373583 0.95062025 + 0.9635416667 0.2630208333 0.9817708333 + 0.9322916667 0.3151041667 0.9817708333 + 0.7955003333 0.039720025 0.2886250917 + 0.95334175 0.1855533583 0.3219005583 + 0.7850836667 0.039720025 0.340708425 + 0.7744815833 0.090369175 0.1863529167 + 0.67153575 0.1133659083 0.2361797167 + 0.9157373333 0.1400141083 0.2243482667 + 0.95334175 0.149095025 0.285442225 + 0.8376123333 0.06188910833 0.2243482667 + 0.6719601667 0.1194544167 0.3195439 + 0.92209175 0.09701169167 0.3271088917 + 0.84396675 0.039720025 0.285442225 + 0.8960500833 0.06576169167 0.301067225 + 0.6386949167 0.1769654083 0.1968249417 + 0.7275856667 0.0742886 0.3600355917 + 0.7375779167 0.06820009167 0.224588075 + 0.8896956667 0.087930775 0.2399732667 + 0.9592560833 0.1963435083 0.1297726583 + 0.7160765 0.191858375 0.1704747083 + 0.8096725 0.1681653667 0.06998078333 + 0.92279775 0.2762045917 0.09591849167 + 0.9201935833 0.15641295 0.058158075 + 0.785821 0.1504279583 0.171594325 + 0.6898180833 0.2042216833 0.09857415 + 0.8108185833 0.2137046167 0.03732474167 + 0.88373525 0.20328795 0.03732474167 + 0.9592560833 0.1859268417 0.077689325 + 0.8749934167 0.174031225 0.193964675 + 0.92279775 0.2328018417 0.05685599167 + 0.9592560833 0.2605795917 0.148001825 + 0.8825891667 0.1369153667 0.09081411667 + 0.7595625833 0.1627912667 0.09969376667 + 0.9216516667 0.1551445333 0.14289745 + 0.9021266667 0.09115865 0.4499715 + 0.9303385 0.12240865 0.4208916667 + 0.9615885 0.18490865 0.4313083333 + 0.91493025 0.1860002 0.383851225 + 0.8083766667 0.052530175 0.4833915833 + 0.9333766667 0.1276169833 0.5072631667 + 0.76368225 0.126818775 0.4031783917 + 0.88368025 0.1235002 0.3734345583 + 0.82118025 0.0922502 0.383851225 + 0.7478405 0.08709875 0.4736389167 + 0.8396266667 0.052530175 0.4347805 + 0.7171950833 0.04201135833 0.6360678333 + 0.9347876667 0.114928025 0.6829428333 + 0.8254126667 0.04201135833 0.6673178333 + 0.65350925 0.1584398667 0.67607725 + 0.6936049167 0.09674515 0.6976600833 + 0.8955986667 0.11391955 0.7507505833 + 0.6508514167 0.13827465 0.5852010833 + 0.8983293333 0.07846969167 0.6412761667 + 0.754821 0.1321950083 0.7593914167 + 0.7811418333 0.04201135833 0.6299914167 + 0.822682 0.07746121667 0.7351255833 + 0.7633573333 0.1291101083 0.5289775833 + 0.70136375 0.07657993333 0.5720616667 + 0.8258466667 0.04201135833 0.5757379167 + 0.8883466667 0.07846969167 0.5844185 + 0.8238935 0.09454153333 0.53873025 + 0.8863935 0.1309998667 0.5474108333 + 0.91493025 0.2415557833 0.368226225 + 0.9125978333 0.238667725 0.2394336333 + 0.95334175 0.2411089417 0.3062755583 + 0.9592560833 0.2840171167 0.206595575 + 0.9615885 0.291028425 0.40721975 + 0.04682281667 0.55954025 0.4079518333 + 0.09036455833 0.53853975 0.4505711667 + 0.121297575 0.4796016667 0.43606325 + 0.2242657417 0.440476275 0.4513761667 + 0.04682281667 0.5067575833 0.31760175 + 0.2002371167 0.39904635 0.3234419333 + 0.09196275833 0.4822444167 0.26135905 + 0.04682281667 0.5521858333 0.3479836667 + 0.122895775 0.43066075 0.3068193 + 0.1407952417 0.5298144167 0.2383632333 + 0.07775583333 0.4551739167 0.363062 + 0.04682281667 0.62626 0.4321850833 + 0.04682281667 0.6084889167 0.3201335833 + 0.0956553 0.6106306667 0.26675585 + 0.2580653417 0.384434125 0.39499755 + 0.06957055833 0.785387 0.2671482333 + 0.07321655 0.8232654167 0.5373885 + 0.1060288917 0.8583036667 0.2931899 + 0.1351485583 0.6681276667 0.3042755167 + 0.1184030417 0.723582 0.24936075 + 0.086316075 0.6764025833 0.4097365833 + 0.112409925 0.9186080833 0.4541863333 + 0.07595159167 0.88214975 0.3604363333 + 0.086316075 0.6659859167 0.35765325 + 0.03949325833 0.7831914167 0.402103 + 0.07595159167 0.8873580833 0.5010613333 + 0.03949325833 0.7140363333 0.39081825 + 0.03949325833 0.8092330833 0.3343946667 + 0.03949325833 0.8248580833 0.4750196667 + 0.1096748833 0.8857654167 0.5634301667 + 0.2160467333 0.7326308333 0.1312184917 + 0.2907827833 0.88599025 0.07302324167 + 0.33244945 0.9224485833 0.109481575 + 0.2245059167 0.7944358333 0.09171430833 + 0.2282827833 0.9224485833 0.1303149083 + 0.29338695 0.8130735833 0.054794075 + 0.170249175 0.8536689167 0.2906923083 + 0.182623325 0.7554055833 0.2312381583 + 0.16721425 0.9038108333 0.2479643083 + 0.1880475833 0.8673525 0.149005975 + 0.19400715 0.9498580833 0.4750196667 + 0.2217691 0.908765 0.378772075 + 0.3064077833 0.9589069167 0.1823982417 + 0.2551925083 0.9589069167 0.351669075 + 0.2100536167 0.9589069167 0.2839607417 + 0.2439077833 0.9589069167 0.203231575 + 0.96875 0.4270833333 0.03125 + 0.96875 0.38715275 0.0703125 + 0.93583625 0.4676649167 0.03125 + 0.34765045 0.8149330833 0.092546325 + 0.34765045 0.9243080833 0.201921325 + 0.3954093333 0.77876925 0.03775225 + 0.3954093333 0.9654011667 0.2243841917 + 0.3736921167 0.88784975 0.1290046583 + 0.4500868333 0.9353298333 0.03645833333 + 0.436642 0.900731 0.07421058333 + 0.4496628333 0.8234740833 0.03775225 + 0.4817708333 0.9717881667 0.07508680833 + 0.453135 0.9654011667 0.190096 + 0.468326 0.9371893333 0.1128390583 + 0.8782915833 0.34442625 0.071549575 + 0.8193361667 0.4197300833 0.032487075 + 0.7741249167 0.3218568333 0.032487075 + 0.6589635 0.29778275 0.0640235 + 0.8687976667 0.3107350333 0.1088743167 + 0.8157915833 0.3635235 0.032487075 + 0.7249904167 0.2736401167 0.1013482417 + 0.905256 0.3298322833 0.1869993167 + 0.8818361667 0.4405634167 0.063737075 + 0.795881 0.27774895 0.06981181667 + 0.7038124167 0.3383499167 0.032487075 + 0.9147499167 0.4017179167 0.102799575 + 0.3303627417 0.4122372083 0.3425231917 + 0.32806115 0.5425249167 0.094990075 + 0.4063725083 0.3097618417 0.226654375 + 0.2725345167 0.4268494333 0.270967575 + 0.3334424417 0.4069450917 0.1283808167 + 0.2440256583 0.5060338333 0.231349125 + 0.415414425 0.3179534417 0.3143631667 + 0.288348675 0.4852185 0.139514125 + 0.31963795 0.3608631083 0.20750345 + 0.713669 0.3091612833 0.1764196167 + 0.6622301667 0.2070589167 0.323724075 + 0.64362925 0.2360898417 0.2421833333 + 0.7419441667 0.214423275 0.3740831 + 0.7210108333 0.2509828083 0.2158331 + 0.5618565833 0.24899375 0.3679031833 + 0.503835 0.333005675 0.3103119083 + 0.31083465 0.6534075833 0.07856500833 + 0.3031188 0.5807808333 0.2258859 + 0.3411484 0.59490475 0.1340509 + 0.2393816417 0.6620584167 0.270419675 + 0.2567791083 0.73151575 0.23337875 + 0.3739813333 0.674414 0.039060825 + 0.3529252 0.7724055 0.13160715 + 0.2902025167 0.708741 0.1333590833 + 0.4006840833 0.7362416667 0.076813075 + 0.6404343333 0.34740525 0.1688478 + 0.5763089167 0.2946725667 0.2000357 + 0.4650525833 0.335512325 0.1772846667 + 0.4404511667 0.3825588417 0.0581238 + 0.6179015833 0.3440021667 0.093776425 + 0.53688825 0.3496535667 0.2239851667 + 0.4243239167 0.4089807583 0.1136096917 + 0.4919564167 0.3275240917 0.089660225 + 0.5412593333 0.33826225 0.06128935 + 0.50447325 0.280531325 0.1533352 + 0.4042286667 0.51578825 0.05548589167 + 0.52360825 0.39966275 0.029752925 + 0.4173159167 0.5681680833 0.09454671667 + 0.4260646667 0.6223306667 0.039060825 + 0.4553976667 0.4605175 0.08523881667 + 0.4715249167 0.4340955833 0.029752925 + 0.561236 0.427549 0.029752925 + 0.6837145 0.4063114167 0.032487075 + 0.6322359167 0.4004475 0.06224 + 0.9506293333 0.51920575 0.03125 + 0.5018748333 0.6161095833 0.039060825 + 0.5227081667 0.6786095833 0.039060825 + 0.4965378333 0.7974324167 0.03775225 + 0.47360075 0.7466583333 0.076813075 + 0.5681423333 0.96875 0.069878475 + 0.5390625 0.9405381667 0.038628475 + 0.6041666667 0.96875 0.03125 + 0.6614583333 0.9427083333 0.03125 + 0.9459999167 0.3947735 0.212174575 + 0.9459999167 0.4329679167 0.165299575 + 0.9835430833 0.5879991667 0.02604166667 + 0.9835430833 0.5463325 0.05729166667 + 0.04947916667 0.669298 0.5544433333 + 0.08854166667 0.6844663333 0.7321641667 + 0.1282211333 0.6358388333 0.74702275 + 0.09302090833 0.60651025 0.6299764167 + 0.04947916667 0.6512375833 0.6711245 + 0.1222649583 0.7557903333 0.7111996667 + 0.04947916667 0.69290425 0.6086245 + 0.1226957167 0.7768756667 0.5474886667 + 0.09630198333 0.6490253333 0.4952366667 + 0.08320245833 0.7503393333 0.6241183333 + 0.139843725 0.59011975 0.5057379167 + 0.1357952417 0.6991679167 0.4727881667 + 0.2322602917 0.53284025 0.6519789167 + 0.132700375 0.57148225 0.6704426667 + 0.09302090833 0.6103924167 0.5649445833 + 0.1613274583 0.9671573333 0.674348 + 0.1821607917 0.9671573333 0.736848 + 0.1873722333 0.8898858333 0.5626968333 + 0.2003930667 0.8122460833 0.5675886667 + 0.2207956417 0.94002775 0.6397605 + 0.2352461667 0.9227285 0.5211613333 + 0.268669575 0.9728704167 0.598225 + 0.3318929917 0.9728704167 0.598225 + 0.2314456833 0.8626766667 0.8749303333 + 0.2000648083 0.7886525833 0.7338576667 + 0.2386996583 0.818572 0.6668763333 + 0.2621371583 0.89621175 0.6880261667 + 0.241731475 0.9233413333 0.7564678333 + 0.2078773083 0.8662923333 0.7914658333 + 0.3069665167 0.956184 0.803474 + 0.4696173333 0.34466625 0.9158515 + 0.447072 0.3984856667 0.9158515 + 0.44663675 0.3466314667 0.7787399167 + 0.558968 0.2622978083 0.7616339167 + 0.5469803333 0.2631030917 0.8561334167 + 0.4946180833 0.31475535 0.7267168333 + 0.4720768333 0.3019401333 0.8597036667 + 0.5316526667 0.3413731667 0.9583279167 + 0.6170348333 0.259594875 0.9539533333 + 0.57692825 0.304961125 0.91228125 + 0.190272575 0.6406425 0.7806438333 + 0.137572275 0.6508796667 0.9019524167 + 0.1407934083 0.62453225 0.8434603333 + 0.2283929583 0.72213225 0.78844325 + 0.2532372417 0.47306875 0.8701525833 + 0.098509775 0.5850988333 0.91165925 + 0.1017309083 0.5587514167 0.8531671667 + 0.1954809083 0.49408125 0.912629 + 0.129759775 0.5434321667 0.94290925 + 0.1329809083 0.51708475 0.8844171667 + 0.2518304583 0.7268553333 0.88250975 + 0.1875 0.7632635 0.9620813333 + 0.1666666667 0.7007635 0.9620813333 + 0.2470706833 0.78976 0.9113886667 + 0.2104889417 0.671713 0.9332024167 + 0.3312179417 0.45207775 0.9575235833 + 0.2070167167 0.5542828333 0.9711210833 + 0.2486833833 0.6167828333 0.9711210833 + 0.2908147167 0.4863953333 0.9286446667 + 0.2330583833 0.5074078333 0.9711210833 + 0.5316526667 0.4038731667 0.9583279167 + 0.4830656667 0.4299148333 0.9583279167 + 0.3385416667 0.9635416667 0.9270833333 + 0.3330081833 0.9197256667 0.8763906667 + 0.296875 0.9270833333 0.9635416667 + 0.3069665167 0.8103506667 0.9493073333 + 0.2913415167 0.8832673333 0.912849 + 0.40625 0.9635416667 0.9635416667 + 0.6795348333 0.3012615417 0.9539533333 + 0.63942825 0.3466277917 0.91228125 + 0.7420348333 0.278692125 0.9539533333 + 0.9615885 0.2814797833 0.4671155833 + 0.9615885 0.2309155917 0.4755791667 + 0.9615885 0.204873925 0.5224541667 + 0.9146053333 0.2082568083 0.5626018333 + 0.9138278333 0.1868362167 0.7481464167 + 0.9530168333 0.2286433 0.6256511667 + 0.960811 0.2151373583 0.8204119167 + 0.9530168333 0.1878446917 0.6803386667 + 0.259994325 0.5927691667 0.7695575 + 0.4134958583 0.5244179167 0.950995 + 0.4732156667 0.4838466667 0.9093229167 + 0.437222 0.4524175 0.8668465 + 0.2975028 0.5493235 0.7174726667 + 0.43432725 0.4432894167 0.78588275 + 0.3370989667 0.5273063333 0.8796396667 + 0.3370299667 0.4705340833 0.76906275 + 0.3775021917 0.49298875 0.9085185833 + 0.2995214917 0.51397975 0.8211475833 + 0.2981147083 0.6742589167 0.7773569167 + 0.3573137667 0.956184 0.7774323333 + 0.383976325 0.9728704167 0.5461416667 + 0.3856064167 0.55807225 0.6536995 + 0.3808044833 0.4731279417 0.3911353083 + 0.3203639083 0.541589 0.58820575 + 0.2676268083 0.57384725 0.5110045 + 0.4672988333 0.3839839083 0.5683511667 + 0.4997435833 0.4212828583 0.3743716833 + 0.3211158083 0.4831418583 0.4711506667 + 0.3738529083 0.4508836083 0.5483519167 + 0.7497045833 0.2191648583 0.5193320833 + 0.7124496667 0.264758 0.434898125 + 0.67510375 0.2283294 0.5607985833 + 0.5415861667 0.366847325 0.5320305 + 0.5750550833 0.2679729 0.5173729167 + 0.5703604167 0.3927571083 0.451601375 + 0.6038293333 0.2938826833 0.4369437917 + 0.8293375833 0.41522825 0.9494464167 + 0.8756520833 0.2679524417 0.9000666667 + 0.7151511667 0.288242575 0.6471678333 + 0.7790370833 0.2266767583 0.7817545 + 0.7662509167 0.3210905417 0.90339975 + 0.9121104167 0.273160775 0.82715 + 0.8210910833 0.36010675 0.9494464167 + 0.6391736667 0.3083598417 0.7672281667 + 0.8835910833 0.3262525833 0.93121725 + 0.70521375 0.2529216167 0.7184055833 + 0.7895619167 0.2523737333 0.8722491667 + 0.689686 0.3508317917 0.8617276667 + 0.86512725 0.2448596333 0.7548845 + 0.5094510833 0.47574075 0.748445 + 0.6762645 0.3722533833 0.6577483333 + 0.6027481667 0.4112146333 0.5860366667 + 0.639394 0.3796482167 0.7333606667 + 0.5002574167 0.5117341667 0.6678518333 + 0.5284608333 0.4283512167 0.6223573333 + 0.5376545 0.3923578 0.7029505 + 0.9200494167 0.3575025833 0.8947589167 + 0.8918375833 0.4100199167 0.9129880833 + 0.96875 0.4010416667 0.9635416667 + 0.9405381667 0.4405381667 0.9635416667 + 0.96875 0.3463541667 0.9453125 + 0.9512994167 0.33666925 0.82184225 + 0.8757566667 0.2864022 0.3527048083 + 0.7915185833 0.2872011167 0.3496511833 + 0.7818443333 0.3529082 0.2335284417 + 0.6782186667 0.4184486667 0.4241669583 + 0.9068263333 0.4170505 0.261757325 + 0.9224149167 0.3358748417 0.3916983333 + 0.7891861667 0.294729725 0.272941925 + 0.7620240833 0.3375358417 0.4104662083 + 0.8660824167 0.3521092833 0.2365820667 + 0.87342425 0.2939308083 0.27599555 + 0.8160340833 0.3576788417 0.4786164167 + 0.8082245 0.2923437833 0.5494765 + 0.7979354167 0.3342953583 0.6348889167 + 0.92278875 0.2999324667 0.6178310833 + 0.8740881667 0.317157275 0.6792566667 + 0.88437725 0.279545975 0.55478175 + 0.9313604167 0.3267272833 0.5061705 + 0.8921868333 0.3568167583 0.4567949167 + 0.75904875 0.4183061667 0.6454694167 + 0.9697719167 0.3991971083 0.5171365 + 0.9305983333 0.4292865833 0.4677609167 + 0.9608264167 0.4518438333 0.4207488333 + 0.9608264167 0.44945675 0.32547975 + 0.9608264167 0.4136494167 0.3738738333 + 0.331914675 0.912463 0.3470132417 + 0.4317568917 0.9535560833 0.4215594417 + 0.3119683333 0.8762845833 0.4644221667 + 0.2489757417 0.715224 0.4420906667 + 0.4096315 0.91895725 0.2822283583 + 0.3796735583 0.9535560833 0.3694761083 + 0.3618726167 0.8778641667 0.2597654917 + 0.2984912667 0.8623210833 0.3741162417 + 0.3372655667 0.6488089167 0.46980575 + 0.3037296583 0.7138778333 0.3252179917 + 0.321127125 0.7833351667 0.2881770667 + 0.279850275 0.7986448333 0.4953556667 + 0.3910168167 0.5950291667 0.3693581417 + 0.3674668167 0.63260025 0.2806842167 + 0.3931890333 0.79887825 0.22590965 + 0.397475075 0.9264265 0.4894025 + 0.48384025 0.9535560833 0.399255275 + 0.5046735833 0.9535560833 0.336755275 + 0.4825481667 0.91895725 0.2718116917 + 0.50001 0.9654011667 0.2161376667 + 0.8651155833 0.48602025 0.1102956 + 0.8549156667 0.5620584167 0.046558525 + 0.74251475 0.4613168333 0.0790456 + 0.7071774167 0.51077075 0.046558525 + 0.7746176667 0.43205625 0.242762225 + 0.90265875 0.5334125833 0.077808525 + 0.8088725833 0.52093425 0.046558525 + 0.9355725 0.5605393333 0.1038501917 + 0.7524489167 0.54437175 0.046558525 + 0.9520294167 0.5402485 0.1663501917 + 0.8026155833 0.4651869167 0.0790456 + 0.85885575 0.46945175 0.23019085 + 0.8980293333 0.4871053333 0.1727956 + 0.5939925833 0.964589 0.1739407917 + 0.6560585833 0.9072973333 0.07281231667 + 0.5905204167 0.8426271667 0.04156231667 + 0.5306345833 0.9017783333 0.1179430417 + 0.60440925 0.933339 0.1114407917 + 0.4902356667 0.8045603333 0.2126778917 + 0.5458255833 0.8392783333 0.07931456667 + 0.5753294167 0.9051271667 0.08019079167 + 0.5318359167 0.88354625 0.2361170667 + 0.54929775 0.9299901667 0.1804430417 + 0.5228885 0.78850425 0.1183753917 + 0.57729575 0.4914054167 0.08488458333 + 0.5379694167 0.737217 0.2300573 + 0.6482956667 0.4643039167 0.1173716583 + 0.6019369167 0.5404550833 0.05513165833 + 0.6789663333 0.5546619167 0.1016901833 + 0.5034829167 0.6036374167 0.3326548 + 0.4799329167 0.6412085 0.243980875 + 0.5700179167 0.6539243333 0.09419248333 + 0.5491845833 0.5914243333 0.09419248333 + 0.57062225 0.7211609167 0.1357548 + 0.5560643333 0.4876858333 0.313423675 + 0.6570721667 0.4318635833 0.1924430333 + 0.7143036667 0.505208 0.1341772583 + 0.7230801667 0.4727676667 0.2092486333 + 0.5643026667 0.4525455833 0.21544185 + 0.7379066667 0.4822155833 0.2654068083 + 0.6636603333 0.47645175 0.3465830333 + 0.4917524167 0.5626524167 0.149678375 + 0.52354075 0.4899410833 0.140370475 + 0.83589975 0.9197605 0.02352893333 + 0.86178775 0.6204351667 0.046558525 + 0.9192330833 0.8364271667 0.02352893333 + 0.78902475 0.9405938333 0.05998726667 + 0.6456419167 0.964589 0.17177065 + 0.7395833333 0.9739583333 0.03645833333 + 0.6875 0.9739583333 0.06770833333 + 0.7419583333 0.9051828333 0.1015495833 + 0.68210025 0.9385473333 0.10927065 + 0.9575014167 0.68305125 0.01692708333 + 0.9739583333 0.74609375 0.01692708333 + 0.9095308333 0.6555914167 0.06348560833 + 0.9355725 0.6243414167 0.089527275 + 0.9835430833 0.65180125 0.04296875 + 0.9400664167 0.7960625833 0.04045601667 + 0.6489023333 0.65238 0.05513165833 + 0.6495066667 0.7196165833 0.096693975 + 0.7050984167 0.6040868333 0.1016901833 + 0.7480664167 0.6096748333 0.046558525 + 0.8113621667 0.6446140833 0.046558525 + 0.69772525 0.855214 0.04156231667 + 0.8254830833 0.8676771667 0.02352893333 + 0.7575833333 0.8530995 0.06509125 + 0.6612669167 0.8187556667 0.04156231667 + 0.6881344167 0.7694754167 0.04156231667 + 0.86714975 0.8260105 0.02352893333 + 0.9520294167 0.57497075 0.2132251917 + 0.9128558333 0.5312755 0.275828775 + 0.9608264167 0.5223734167 0.32547975 + 0.9520294167 0.6270540833 0.202808525 + 0.9520294167 0.6561339167 0.1416106083 + 0.94527475 0.865073 0.0573831 + 0.9661080833 0.8247084167 0.07431018333 + 0.9791666667 0.8984375 0.03385416667 + 0.9453125 0.9401041667 0.07291666667 + 0.8697539167 0.9458021667 0.06259143333 + 0.9036458333 0.9791666667 0.0390625 + 0.9114205833 0.9067396667 0.0964456 + 0.8228789167 0.9666355 0.09904976667 + 0.38138935 0.913442 0.72375075 + 0.40327125 0.957258 0.6754850833 + 0.3514477833 0.8863124167 0.68135075 + 0.4090804167 0.6581389167 0.6445233333 + 0.3280102833 0.8086726667 0.6602009167 + 0.476634 0.957258 0.5826031667 + 0.4389117667 0.8836845 0.5242625833 + 0.4592729167 0.957258 0.6451031667 + 0.3590971833 0.7308799167 0.7160959167 + 0.3733296833 0.9301284167 0.6330850833 + 0.4134766667 0.7166173333 0.5378308333 + 0.3633909333 0.80604475 0.5551960833 + 0.4254130167 0.9301284167 0.58100175 + 0.453559 0.9635416667 0.9249131667 + 0.460553 0.9494551667 0.8264860833 + 0.3729882667 0.7962641667 0.91338025 + 0.4329314333 0.7579748333 0.7742353333 + 0.336081375 0.7333595 0.8845013333 + 0.4317861 0.8628971667 0.7607403333 + 0.3719489583 0.7013538333 0.8354963333 + 0.4077105167 0.9056391667 0.8144219167 + 0.4518724167 0.9129968333 0.8889860833 + 0.3990299333 0.8691808333 0.8769219167 + 0.568858 0.4528905 0.92683125 + 0.6582459167 0.4581166667 0.7963635 + 0.56573075 0.5087125833 0.7979120833 + 0.5266005833 0.5076904167 0.87782625 + 0.6010676667 0.48908125 0.9685033333 + 0.6635676667 0.4682479167 0.9685033333 + 0.631358 0.4320571667 0.92683125 + 0.68161575 0.4362611667 0.8762776667 + 0.4191491083 0.6635725833 0.886189 + 0.5146238333 0.5786435833 0.9194983333 + 0.51293725 0.65309875 0.88357125 + 0.33722505 0.6341439167 0.9711210833 + 0.4360411917 0.57650125 0.950995 + 0.383281525 0.69557825 0.935194 + 0.3730926333 0.60213825 0.9221160833 + 0.4201884167 0.7584829167 0.9640729167 + 0.5967274167 0.5527386667 0.9685033333 + 0.552541 0.5875010833 0.9685033333 + 0.6513425833 0.58432625 0.9685033333 + 0.5056423333 0.9270833333 0.9613715 + 0.4983134167 0.79494125 0.9640729167 + 0.50395575 0.8765385 0.9254444167 + 0.5989583333 0.9635416667 0.96875 + 0.562934 0.9635416667 0.9301215 + 0.7038205 0.5715774167 0.93747825 + 0.7776539167 0.5018231667 0.9689749167 + 0.8097669167 0.4626645833 0.9184213333 + 0.8722669167 0.45745625 0.881963 + 0.7204485 0.5018534167 0.8070105 + 0.7117053333 0.5191565 0.93747825 + 0.7438183333 0.4799979167 0.8869246667 + 0.7615225833 0.5824559167 0.9689749167 + 0.8036955833 0.5486981667 0.9689749167 + 0.9209675 0.5140161667 0.89605825 + 0.8845091667 0.5660995 0.9325165833 + 0.9635416667 0.59375 0.9635416667 + 0.9353298333 0.5499131667 0.9635416667 + 0.9717881667 0.4978298333 0.9270833333 + 0.9512994167 0.39135675 0.7584741667 + 0.9697719167 0.3829211083 0.6267285 + 0.9697719167 0.4350044417 0.5746451667 + 0.9210713333 0.4001459167 0.6881540833 + 0.9697719167 0.5044489167 0.5905595 + 0.5278944167 0.6582680833 0.6730533333 + 0.52342475 0.72428025 0.7593915 + 0.5562304167 0.6571854167 0.81803475 + 0.5689906667 0.57703225 0.6832790833 + 0.68744225 0.5798610833 0.7920275833 + 0.5970471667 0.5837524167 0.7740476667 + 0.4998195833 0.9067131667 0.748933 + 0.5054245 0.957258 0.6815615 + 0.507428 0.9494551667 0.8004444167 + 0.5575078333 0.957258 0.6451031667 + 0.5990225 0.7850683333 0.317080725 + 0.53714725 0.9224215 0.4480825833 + 0.5265005833 0.8796795 0.5052468333 + 0.5828209167 0.9688654167 0.4729930833 + 0.6127809167 0.9688654167 0.5430403333 + 0.5769606667 0.9261234167 0.5836874167 + 0.5422384167 0.9261234167 0.55764575 + 0.5780586667 0.9688654167 0.5169986667 + 0.5889113333 0.6437241667 0.4064836583 + 0.7931044167 0.4638159167 0.4938971667 + 0.7011155833 0.4895114167 0.4784103333 + 0.607769 0.6718576667 0.6013730833 + 0.7608035833 0.5532783333 0.3196501833 + 0.6544193333 0.5081871667 0.5598509167 + 0.6452720833 0.7572800833 0.5997225833 + 0.5526563333 0.7029243333 0.5112120833 + 0.64886525 0.5906218333 0.6115988333 + 0.6264144167 0.7291465833 0.4048331583 + 0.5901594167 0.78834675 0.5095615833 + 0.68655725 0.5475145 0.4008264083 + 0.7464081667 0.4824916667 0.57533775 + 0.750247 0.5918429167 0.7490181667 + 0.93841625 0.5315939167 0.6410534167 + 0.8770750833 0.5652611667 0.6019654167 + 0.7397265 0.6093238333 0.659358 + 0.8897156667 0.47937425 0.6865646667 + 0.91994375 0.4705850833 0.75688475 + 0.8691230833 0.4867714167 0.8074569167 + 0.78325325 0.51383525 0.7640010833 + 0.9686443333 0.527145 0.77098 + 0.9178236667 0.5433313333 0.8215521667 + 0.8038458333 0.4803964167 0.68824775 + 0.79120525 0.5445819167 0.6181160833 + 0.9804116667 0.5666331667 0.4384445833 + 0.9804116667 0.5830298333 0.49617025 + 0.91101 0.4945936667 0.465595 + 0.9412380833 0.5171509167 0.4185829167 + 0.9412380833 0.5518731667 0.3717079167 + 0.8888424167 0.5676159167 0.5351996667 + 0.9804116667 0.6013554167 0.3915695833 + 0.9501835833 0.5339486667 0.5308849167 + 0.8496688333 0.5282609167 0.46990975 + 0.8932675 0.56077525 0.3220569417 + 0.8319263333 0.55972025 0.3732466917 + 0.58402225 0.9224215 0.4133603333 + 0.5645694167 0.9535560833 0.3497760833 + 0.6116085833 0.8870105 0.3522268167 + 0.6296959167 0.9688654167 0.4382708333 + 0.59215575 0.9181450833 0.2886425667 + 0.6873085833 0.964589 0.2134373167 + 0.6768919167 0.964589 0.2672567333 + 0.7871596667 0.828965 0.1282158167 + 0.8082221667 0.9498238333 0.2115620667 + 0.7715346667 0.8810483333 0.16467415 + 0.75334325 0.9144128333 0.2140618833 + 0.7251019167 0.7254143333 0.373655225 + 0.7155413333 0.7319404167 0.1598185417 + 0.961868 0.77664675 0.16598915 + 0.7429265833 0.9144128333 0.2678813 + 0.7102960833 0.88327825 0.3210488833 + 0.88785575 0.7101244167 0.126610175 + 0.8168605 0.7495019167 0.06312456667 + 0.82097325 0.6907920833 0.1096830917 + 0.69771 0.7813360833 0.2859027917 + 0.8264135833 0.9164593333 0.1621743333 + 0.8498510833 0.7966676667 0.0866535 + 0.8941219167 0.8773968333 0.1595701667 + 0.9138974167 0.67583625 0.239891425 + 0.9138974167 0.7049160833 0.1786935083 + 0.7563038333 0.65655825 0.16481475 + 0.7541690833 0.78179925 0.1046868833 + 0.8943090833 0.6532526667 0.2965362583 + 0.7618451667 0.64575575 0.2941295 + 0.8329679167 0.6521976667 0.3477260083 + 0.9279760833 0.8161989167 0.13743475 + 0.9019344167 0.7875530833 0.1035805833 + 0.961868 0.7241294167 0.2974995667 + 0.9422796667 0.7015458333 0.3541444 + 0.9804116667 0.6585506667 0.39952675 + 0.961868 0.7779488333 0.2870829 + 0.8759305 0.9133655 0.2428120667 + 0.9280138333 0.874303 0.2037495667 + 0.961868 0.8013863333 0.2167704 + 0.9661458333 0.9244791667 0.1822916667 + 0.9661458333 0.9609375 0.1145833333 + 0.94921875 0.9635416667 0.2096354167 + 0.8971354167 0.9635416667 0.2408854167 + 0.5986973333 0.92943125 0.6988570833 + 0.5622885 0.8788864167 0.7618883333 + 0.6028335 0.97217325 0.8180768333 + 0.6080418333 0.9357149167 0.8805768333 + 0.5698969167 0.9216284167 0.81339975 + 0.5847483333 0.8013758333 0.7588518333 + 0.6181501667 0.8982966667 0.6374413333 + 0.6267210833 0.8207860833 0.6708631667 + 0.57510525 0.8851700833 0.87589975 + 0.63879775 0.7712011667 0.84899175 + 0.5812363333 0.6851044167 0.93257625 + 0.6592395 0.62776925 0.9685033333 + 0.6046243333 0.6395844167 0.9685033333 + 0.6245295 0.6891910833 0.86703975 + 0.7694195 0.6258989167 0.9689749167 + 0.7117174167 0.6150204167 0.93747825 + 0.7003954167 0.63092225 0.87194175 + 0.5764384167 0.7584829167 0.9640729167 + 0.62154625 0.8122534167 0.91452825 + 0.657087 0.91748575 0.9192053333 + 0.6536458333 0.9453125 0.96875 + 0.6779203333 0.8445690833 0.9504553333 + 0.6848958333 0.9817708333 0.9427083333 + 0.688337 0.9539440833 0.8931636667 + 0.7369791667 0.9817708333 0.9739583333 + 0.6701078333 0.97217325 0.804622 + 0.7065661667 0.97217325 0.8410803333 + 0.8868735833 0.6307810833 0.82251525 + 0.80516675 0.6522288333 0.7934370833 + 0.80885425 0.6557194167 0.9334796667 + 0.8817709167 0.62967775 0.8970213333 + 0.76360575 0.6771671667 0.8679431667 + 0.8232165833 0.7072414167 0.96450475 + 0.73453425 0.7581540833 0.8494235833 + 0.9325915833 0.6681789167 0.90981725 + 0.9325915833 0.76713725 0.9462755833 + 0.9635416667 0.7473958333 0.9817708333 + 0.9270833333 0.6901041667 0.9817708333 + 0.9635416667 0.6484375 0.9453125 + 0.89613325 0.7098455833 0.9462755833 + 0.9190705 0.6412196667 0.5364129167 + 0.9073031667 0.6388649167 0.6031786667 + 0.9804116667 0.6801796667 0.4658365833 + 0.9804116667 0.6393810833 0.5156050833 + 0.9686443333 0.60527 0.7345216667 + 0.93769425 0.6666780833 0.7806236667 + 0.9686443333 0.657281 0.65094725 + 0.9690499167 0.6942205833 0.8369005833 + 0.9686443333 0.60092975 0.6749151667 + 0.8998091667 0.7240269167 0.73850225 + 0.8181023333 0.719433 0.7458824167 + 0.7343530833 0.7584125833 0.61128275 + 0.78771125 0.6916921667 0.6606924167 + 0.7158020833 0.8219185833 0.6824233333 + 0.93075925 0.7189700833 0.6684323333 + 0.7695658333 0.78946125 0.7708438333 + 0.68059075 0.9410386667 0.6472860833 + 0.7656139167 0.93056375 0.7394970833 + 0.6993323333 0.97217325 0.7555768333 + 0.7329834167 0.8994291667 0.6676646667 + 0.6611379167 0.97217325 0.7087018333 + 0.6713625833 0.9688654167 0.5213389167 + 0.6835153333 0.9688654167 0.460575 + 0.6979829167 0.9688654167 0.57183075 + 0.7690674167 0.878223 0.4076280667 + 0.7860981667 0.7954569167 0.55496075 + 0.7446994167 0.9283991667 0.4695035 + 0.9504499167 0.73288475 0.4854711667 + 0.88910875 0.704052 0.51061925 + 0.8773414167 0.70169725 0.577385 + 0.9007975 0.7514205 0.6194905 + 0.8394563333 0.7287365 0.6043704167 + 0.7829138333 0.8867896667 0.5953508333 + 0.7582989167 0.9283991667 0.5489305833 + 0.78585125 0.78689025 0.4466650667 + 0.85097675 0.7225245833 0.4293089833 + 0.9123179167 0.7513573333 0.4041609 + 0.883743 0.9133655 0.3027079 + 0.805618 0.9498238333 0.3252773167 + 0.8277395833 0.9093575833 0.38050215 + 0.9049479167 0.9635416667 0.30078125 + 0.8033715833 0.95953375 0.4423775833 + 0.961868 0.8196155 0.3287495667 + 0.93190625 0.8156075833 0.3891827333 + 0.9058645833 0.8781075833 0.3839744 + 0.9358263333 0.8821155 0.3235412333 + 0.97003825 0.82715525 0.4454158333 + 0.97003825 0.7897565 0.4961006667 + 0.9830729167 0.9635416667 0.25390625 + 0.95703125 0.9635416667 0.3111979167 + 0.9739583333 0.9322916667 0.34375 + 0.7852083333 0.8264618333 0.9715196667 + 0.7417745 0.85592675 0.921975 + 0.8161685 0.8418711667 0.8079 + 0.9076041667 0.8551076667 0.9715196667 + 0.8974874167 0.8123490833 0.9360244167 + 0.8320833333 0.9358368333 0.9715196667 + 0.8372916667 0.8785451667 0.9715196667 + 0.7852083333 0.9566701667 0.945478 + 0.7469828333 0.9288434167 0.8959333333 + 0.765212 0.9470725833 0.84385 + 0.79503525 0.9054630833 0.7913119167 + 0.82457075 0.7810990833 0.9360244167 + 0.7811369167 0.810564 0.88647975 + 0.9440625 0.891566 0.9506863333 + 0.9690499167 0.8035955833 0.92544225 + 0.93394575 0.8488074167 0.9151910833 + 0.8346875 0.9748993333 0.9246446667 + 0.9232291667 0.9332326667 0.929853 + 0.8815625 0.954066 0.9506863333 + 0.8242708333 0.9748993333 0.8725613333 + 0.9166666667 0.9791666667 0.9791666667 + 0.9791666667 0.9166666667 0.9791666667 + 0.9583333333 0.9583333333 0.9583333333 + 0.8194644167 0.9583905 0.7213334167 + 0.84888575 0.9332898333 0.77314825 + 0.8659375 0.9748993333 0.8308946667 + 0.93394575 0.85401575 0.8578994167 + 0.9311648333 0.7854235833 0.7557166667 + 0.9009690833 0.8968315 0.7679399167 + 0.8960606667 0.8332395833 0.800153 + 0.9690499167 0.7567205833 0.81606725 + 0.9690499167 0.8088039167 0.8681505833 + 0.9321531667 0.8128171667 0.59503825 + 0.9621149167 0.78036675 0.6439800833 + 0.93607325 0.8854738333 0.6974619167 + 0.9621149167 0.8125571667 0.6922535833 + 0.97003825 0.8157981667 0.5429756667 + 0.84029775 0.9583905 0.6692500833 + 0.90482325 0.9219321667 0.6505869167 + 0.9009031667 0.8814659167 0.59643675 + 0.8502465833 0.95953375 0.4979331667 + 0.81176275 0.95953375 0.5686796667 + 0.8363776667 0.91792425 0.6150999167 + 0.9739583333 0.96875 0.4010416667 + 0.97003825 0.88965525 0.4662491667 + 0.97003825 0.8844469167 0.5235408333 + 0.9439965833 0.92828375 0.4458498333 + 0.93878825 0.9230754167 0.5500165 + 0.9127465833 0.95953375 0.4979331667 + 0.9388541667 0.938441 0.804853 + 0.9791666667 0.9791666667 0.9166666667 + 0.9440625 0.954066 0.8881863333 + 0.9180208333 0.9748993333 0.8413113333 + 0.9648958333 0.9176076667 0.851728 + 0.9739583333 0.9635416667 0.75 + 0.96875 0.9635416667 0.5885416667 + 0.9427083333 0.9635416667 0.6458333333 + 0.9739583333 0.9270833333 0.6927083333 + 0 0.02777777778 0.9166666667 + 0.1006944444 0 0.9479166667 + 0.08333333333 0.02777777778 1 + 0.04513888889 0 0.8923611111 + 0.02256944444 0 0.7517361111 + 0 0.03819444444 0.7534722222 + 0.02256944444 0 0.2482638889 + 0 0.03472222222 0.2569444444 + 0 0.0625 0.1736111111 + 0.06770833333 0 0.1892361111 + 0.04513888889 0 0.1076388889 + 0 0.02777777778 0.08333333333 + 0 0.08333333333 0.02777777778 + 0.02777777778 0.08333333333 0 + 0.08333333333 0.02777777778 0 + 0.1006944444 0 0.05208333333 + 0 0.2569444444 0.03472222222 + 0.02604166667 0.2511574111 0 + 0.1736111111 0.0625 0 + 0.1909722222 0 0.1006944444 + 0.2569444444 0.03472222222 0 + 0.2569444444 0 0.04861111111 + 0.02777777778 0.08333333333 1 + 0 0.08333333333 0.9722222222 + 0 0.1597222222 0.9236111111 + 0 0.06597222222 0.8368055556 + 0 0.1423611111 0.84375 + 0.06770833333 0 0.8107638889 + 0.05092592222 0.1666666667 1 + 0.1909722222 0 0.8993055556 + 0.2511574111 0.02604166667 1 + 0.2569444444 0 0.9513888889 + 0.1678240778 0.05381944444 1 + 0.1203703667 0.1805555556 1 + 0.1817129667 0.1232638889 1 + 0.05729166667 0 0.3246527778 + 0 0.07986111111 0.6701388889 + 0.05729166667 0 0.6753472222 + 0 0.07638888889 0.3402777778 + 0 0.04166666667 0.5833333333 + 0.03472222222 0 0.5902777778 + 0.03472222222 0 0.4097222222 + 0 0.04166666667 0.4166666667 + 0.1371527778 0 0.7690972222 + 0.2048611111 0 0.8020833333 + 0 0.1770833333 0.6840277778 + 0 0.2118055556 0.7743055556 + 0.1267361111 0 0.6892361111 + 0.02777777778 0.9166666667 0 + 0 0.9166666667 0.02777777778 + 0 0.9722222222 0.08333333333 + 0.02777777778 1 0.08333333333 + 0.08333333333 1 0.02777777778 + 0.08333333333 0.9722222222 0 + 0.7517361111 0.02256944444 0 + 0.7430555556 0 0.03472222222 + 0.5902777778 0.03472222222 0 + 0.5752314444 0 0.03009258889 + 0 0.1736111111 0.0625 + 0.05381944444 0.1678240778 0 + 0.078125 0.3090277444 0 + 0 0.3171296667 0.09490741111 + 0 0.275463 0.1643518556 + 0 0.1319444444 0.1875 + 0 0.1875 0.1319444444 + 0 0.1747685222 0.3231095667 + 0 0.3020833 0.3925540111 + 0 0.2233796333 0.3994984556 + 0 0.4305555556 0.04166666667 + 0.0390625 0.4338348889 0 + 0 0.3796296667 0.1018518556 + 0.09114583333 0.3805941111 0 + 0.03819444444 0.7534722222 0 + 0 0.7395833333 0.02430555556 + 0.5208333333 0.07638888889 0 + 0.505787 0 0.07175925556 + 0.4305555556 0.04166666667 0 + 0.4305555556 0 0.04166666667 + 0.1371527778 0 0.2309027778 + 0.3287036667 0 0.3125 + 0.1267361111 0 0.3107638889 + 0.2048611111 0 0.1979166667 + 0.2986111111 0 0.2291666667 + 0 0.2025463 0.2536651222 + 0.3819444444 0 0.1736111111 + 0.3541666667 0 0.09027777778 + 0.1875 0.1319444444 0 + 0.1475694444 0.2673610778 0 + 0.1232638889 0.1817129667 0 + 0.3796296667 0.1018518556 0 + 0.275463 0.1643518556 0 + 0.3171296667 0.09490741111 0 + 0.07986111111 0.6701388889 0 + 0 0.5208333333 0.09027777778 + 0.08072916667 0.5171682222 0 + 0 0.6631944444 0.07291666667 + 0 0.5902777778 0.04861111111 + 0.04166666667 0.5833333333 0 + 0.4074074444 0.1851851889 0 + 0.4444444444 0.04166666667 1 + 0.4027777778 0 0.9583333333 + 0.4554397778 0 0.9207175556 + 0 0.2430555556 0.9513888889 + 0.02314814444 0.25 1 + 0 0.9375 0.8263888889 + 0 0.9722222222 0.9166666667 + 0.02777777778 1 0.9166666667 + 0.02777777778 0.9166666667 1 + 0 0.9166666667 0.9722222222 + 0.08333333333 1 0.9722222222 + 0.08333333333 0.9722222222 1 + 0 0.3194444444 0.9027777778 + 0.06944444444 0.3055555556 1 + 0.1388888889 0.2638888889 1 + 0 0.3726852222 0.7708333333 + 0 0.3055555556 0.8055555556 + 0.3541666667 0 0.8263888889 + 0.2986111111 0 0.7708333333 + 0.3912036667 0.09375 1 + 0.3263888889 0 0.9097222222 + 0.3090277444 0.078125 1 + 0.2673610778 0.1475694444 1 + 0.2314815222 0.2847222222 1 + 0.2986111111 0.2256944444 1 + 0 0.2222222222 0.5972222222 + 0 0.3043981111 0.5983796667 + 0 0.3645833333 0.681713 + 0 0.4320987778 0.6527777778 + 0 0.4552468889 0.5694444444 + 0.2731481111 0 0.3958333333 + 0 0.1666666667 0.5 + 0.06944444444 0 0.5 + 0.1527777778 0 0.5 + 0.1875 0 0.3958333333 + 0 0.08333333333 0.5 + 0.1875 0 0.6041666667 + 0.5347222222 0.07638888889 1 + 0.7569444444 0 0.9513888889 + 0.7517361111 0.02256944444 1 + 0.6753472222 0.05729166667 1 + 0.5902777778 0 0.9513888889 + 0.5902777778 0.03472222222 1 + 0.5318286667 0 0.9137731111 + 0.6805555556 0 0.9027777778 + 0.8923611111 0.04513888889 1 + 0.9166666667 0 0.9722222222 + 0.449074 0 0.3356481111 + 0.324074 0 0.5 + 0.3287036667 0 0.6875 + 0.2731481111 0 0.6041666667 + 0.4768517778 0 0.4189814444 + 0.4074073333 0 0.5 + 0.4480773333 0 0.5670332222 + 0.4202995556 0 0.6503665556 + 0.9722222222 0 0.9166666667 + 1 0.02777777778 0.9166666667 + 1 0.08333333333 0.9722222222 + 0.9479166667 0.1006944444 1 + 0.9652777778 0 0.2569444444 + 1 0.03472222222 0.2569444444 + 0.5309606667 0.1463155889 0 + 0.7038966667 0 0.2241512333 + 0.6354166667 0 0.125 + 0.6753472222 0.05729166667 0 + 0.6516203333 0 0.06481481111 + 0.712963 0 0.1643518556 + 0.5451388889 0 0.1319444444 + 0.8680555556 0 0.1875 + 0.8125 0 0.1319444444 + 0.8263888889 0 0.0625 + 0.9375 0 0.1736111111 + 0.9166666667 0 0.02777777778 + 0.8923611111 0.04513888889 0 + 0.8107638889 0.06770833333 0 + 1 0.02777777778 0.08333333333 + 0.9722222222 0 0.08333333333 + 1 0.0625 0.1736111111 + 0.9479166667 0.1006944444 0 + 1 0.08333333333 0.02777777778 + 0.9236111111 0 0.3263888889 + 1 0.07638888889 0.3263888889 + 0.9583333333 0 0.4027777778 + 1 0.04166666667 0.4027777778 + 1 0.1319444444 0.1875 + 0 0.3275462222 0.494213 + 0 0.4108795556 0.494213 + 0 0.3576388556 0.3092206778 + 0 0.4480773333 0.4329667778 + 0 0.4202995556 0.3496334444 + 0 0.9236111111 0.1597222222 + 0 0.7604166667 0.1979166667 + 0 0.8298611111 0.1284722222 + 0 0.6770833333 0.1701388889 + 0 0.8229166667 0.05208333333 + 0.06597222222 0.8368055556 0 + 0.1597222222 0.9236111111 0 + 0.1423611111 0.84375 0 + 0 0.9583333333 0.4166666667 + 0.04861111111 1 0.4097222222 + 0 0.9097222222 0.3263888889 + 0 0.9513888889 0.2430555556 + 0.04861111111 1 0.2430555556 + 0.09722222222 1 0.3194444444 + 0.07638888889 1 0.1597222222 + 0.1770833333 1 0.05208333333 + 0.2604166667 1 0.02430555556 + 0.2430555556 0.9513888889 0 + 0.1701388889 1 0.1284722222 + 0.3194444444 0.9027777778 0 + 0.3368055556 1 0.07291666667 + 0.7690972222 0.1371527778 0 + 0.6892361111 0.1267361111 0 + 0.614294 0.1740933667 0 + 0.9513888889 0.2569444444 0 + 1 0.2511574111 0.02604166667 + 0.2256944444 0.2986111111 0 + 0.2395833333 0.3958333333 0 + 0 0.4814814444 0.2083333333 + 0 0.3530093 0.2374614222 + 0.1744791667 0.4361496667 0 + 0.1640625 0.5171682222 0 + 0 0.4074074444 0.1851851889 + 0 0.2835648556 0.2235725333 + 0 0.5439814444 0.1736111111 + 0 0.6273147778 0.2291666667 + 0.2118055556 0.7743055556 0 + 0.1770833333 0.6840277778 0 + 0.6298225556 0 0.2750771222 + 0.4976852222 0 0.1851851889 + 0.5347222222 0 0.2638888556 + 0.4684606667 0.1949267 0 + 0.3587963333 0.2592593 0 + 0.2893518889 0.2453704111 0 + 0.3090277778 0.4405864444 0 + 0.2520254444 0.6353202222 0 + 0.2381365556 0.5658757778 0 + 0.3179976667 0.5296103333 0 + 0.4021991111 0.3219522222 0 + 0.384838 0.3967978889 0 + 0.4748264444 0.2761381444 0 + 0.6038773333 0.2516397 0 + 0.5269097778 0.3050733667 0 + 0.4097222222 1 0.04861111111 + 0.4097222222 0.9513888889 0 + 0.9097222222 0.3263888889 0 + 1 0.3090277444 0.078125 + 0 0.9652777778 0.7430555556 + 0.02430555556 1 0.7395833333 + 0.05208333333 1 0.8229166667 + 0 0.9166666667 0.5 + 0 0.9583333333 0.5833333333 + 0.04861111111 1 0.5902777778 + 0.09722222222 1 0.5 + 0 0.7727623333 0.5966435556 + 0 0.8213734444 0.6730324444 + 0.07291666667 1 0.6631944444 + 0 0.9236111111 0.6597222222 + 0.489744 0 0.6989776667 + 0.427662 0 0.8373842222 + 0.4924767778 0 0.7957175556 + 0.5549767778 0 0.8304397778 + 0.550315 0 0.6584684444 + 0.5347222222 0.1597222222 1 + 0.4467592222 0.1770833333 1 + 0 0.7935956667 0.7424768889 + 0 0.6824845556 0.8258102222 + 0 0.7380401111 0.7980324444 + 0 0.8680555556 0.8125 + 0 0.8263888889 0.9375 + 0 0.6338734444 0.7771991111 + 0 0.8125 0.8680555556 + 0.02430555556 0.7395833333 1 + 0 0.7430555556 0.9652777778 + 0 0.6736111111 0.9236111111 + 0.05208333333 0.8229166667 1 + 0 0.4097222222 0.9513888889 + 0.04166666667 0.4305555556 1 + 0 0.4681713333 0.9137731111 + 0.08796296667 0.375 1 + 0.09027777778 0.5208333333 1 + 0 0.5972222222 0.9583333333 + 0.04861111111 0.5902777778 1 + 0 0.5445602222 0.9207175556 + 0.07291666667 0.6631944444 1 + 0.1712963 0.4027777778 1 + 0.2453704111 0.3541666667 1 + 0.1284722222 1 0.8298611111 + 0.1597222222 1 0.9236111111 + 0.1284722222 0.8298611111 1 + 0.1597222222 0.9236111111 1 + 0.2430555556 1 0.9513888889 + 0.2430555556 0.9513888889 1 + 0.9207175556 0 0.4554397778 + 1 0.0931713 0.4508102222 + 0.9270833333 0 0.6631944444 + 0.9137731111 0 0.5318286667 + 0.9513888889 0 0.5902777778 + 1 0.04861111111 0.5902777778 + 1 0.1001157444 0.5271991111 + 1 0.09722222222 0.6805555556 + 1 0.07638888889 0.8402777778 + 0.9479166667 0 0.8229166667 + 0.9756944444 0 0.7395833333 + 1 0.04861111111 0.7569444444 + 0 0.572338 0.8373842222 + 0 0.4450232222 0.8304397778 + 0 0.5075232222 0.7957175556 + 0 0.5027006667 0.7071758889 + 0.3958333333 0.2395833333 1 + 0.4405864444 0.3090277778 1 + 0.410526 0.380787 1 + 0.3356803333 0.3981481111 1 + 0 0.5273276667 0.4643132222 + 0 0.5721451111 0.6585647778 + 0 0.5773213333 0.5718556667 + 0 0.531025 0.5371334444 + 0.6550925556 0 0.4182098889 + 0.673804 0 0.3537808222 + 0.6647376667 0 0.5582562222 + 0.7152777778 0 0.4876543333 + 0.5814043333 0 0.5351081111 + 0.5717592222 0 0.4459876667 + 0.7690972222 0.1371527778 1 + 0.8107638889 0.06770833333 1 + 0.8402777778 0 0.9236111111 + 0.8715277778 0 0.8298611111 + 0.8020833333 0 0.7604166667 + 0.6892361111 0.1267361111 1 + 0.6944444444 0 0.8055555556 + 0.6273147778 0 0.7708333333 + 0.6253857778 0 0.6956018889 + 0.6041666667 0.1875 1 + 0.8993055556 0.1909722222 1 + 0.8020833333 0.2048611111 1 + 0.5271668889 0 0.5751351111 + 1 0.1701388889 0.8715277778 + 1 0.1770833333 0.9479166667 + 1 0.2604166667 0.9756944444 + 0.9513888889 0.2569444444 1 + 0.9097222222 0.3263888889 1 + 0.7895447778 0 0.2889660444 + 1 0.1944444444 0.3333333333 + 0.7756558889 0 0.3584104889 + 1 0.1458333333 0.2847222222 + 0.8541666667 0 0.2847222222 + 1 0.1817129667 0.1232638889 + 0.8020833333 0.2048611111 0 + 0.8993055556 0.1909722222 0 + 1 0.1678240778 0.05381944444 + 1 0.2673610778 0.1475694444 + 1 0.1765046333 0.4230324444 + 0.7957175556 0 0.4924767778 + 0.8373842222 0 0.427662 + 0.685571 0 0.6354166667 + 0.8298611111 0 0.6770833333 + 0.7708333333 0 0.6273147778 + 0.8304397778 0 0.5549767778 + 1 0.2685185556 0.3125 + 1 0.2986111111 0.2256944444 + 1 0.3179976667 0.3909143333 + 0 0.5601208889 0.4214891111 + 0 0.489744 0.3010223333 + 0 0.550315 0.3415315556 + 0 0.6490805556 0.4538001111 + 0 0.6253857778 0.3043981111 + 0 0.7777777778 0.4027777778 + 0 0.685571 0.3877314444 + 0 0.8125 0.3125 + 0 0.8333333333 0.5 + 0.3055555556 0.8055555556 0 + 0.2060185222 1 0.5 + 0.3229166667 1 0.1701388889 + 0.2546296333 1 0.3958333333 + 0.1944444444 1 0.3055555556 + 0.2395833333 1 0.1979166667 + 1 0.4444444444 0.04166666667 + 0.9583333333 0.4027777778 0 + 1 0.3912036667 0.09375 + 0.9144483333 0.4568865556 0 + 0.3784722222 0.7511574444 0 + 0.3784722222 1 0.2488425889 + 0.4681713333 0.9137731111 0 + 0.4508102222 0.8107638889 0 + 0.4728008889 1 0.1001157444 + 0.4554397778 1 0.203125 + 0.831115 0.4291087778 0 + 0.7708333333 0.2986111111 0 + 0.8263888889 0.3541666667 0 + 0.6770833333 0.3206018889 0 + 0.3596643333 0.6711998889 0 + 0.401331 0.5296103333 0 + 0.5167824444 0.4018133333 0 + 0.4291087778 0.6017554444 0 + 0.447338 0.4477237778 0 + 0.5669527778 0.438995 0 + 0.6502861111 0.4112172222 0 + 0.9341724444 0.5256076667 0 + 0.530189 0.5934606667 0 + 0.5579667778 0.676794 0 + 0.5133102222 0.7760416667 0 + 0.5491897778 1 0.0931713 + 0.5445602222 0.9207175556 0 + 0.5972222222 0.9583333333 0 + 0.5972222222 1 0.04166666667 + 0.6736111111 0.9236111111 0 + 1 0.3958333333 0.2395833333 + 1 0.4467592222 0.1770833333 + 0.9780574444 0.58261 0 + 1 0.5902777778 0.03472222222 + 1 0.5347222222 0.07638888889 + 0 0.6625836667 0.5313464444 + 0 0.6385031111 0.6869213333 + 0 0.6940586667 0.603588 + 0.1701388889 1 0.6770833333 + 0.1979166667 1 0.7604166667 + 0.2546296333 1 0.6041666667 + 0.3389275222 1 0.6041666667 + 0.3055555556 1 0.8055555556 + 0.5262345556 0.3252314444 1 + 0.6041666667 0.2731481111 1 + 0.1979166667 0.7604166667 1 + 0.1701388889 0.6770833333 1 + 0.3229488111 0.4780092222 1 + 0.1932870333 0.5381944444 1 + 0.2488425889 0.6215277778 1 + 0.2280092556 0.4756944444 1 + 0.5262345556 0.4085647778 1 + 0.4614518889 0.443287 1 + 0.3194444444 1 0.9027777778 + 0.3194444444 0.9027777778 1 + 0.3055555556 0.8055555556 1 + 0.4097222222 1 0.9513888889 + 0.4097222222 0.9513888889 1 + 0.6875 0.3287036667 1 + 0.7708333333 0.2986111111 1 + 1 0.3052661444 0.4707754444 + 1 0.2378472222 0.4820602222 + 1 0.203125 0.5445602222 + 1 0.2488425889 0.6215277778 + 1 0.2395833333 0.8020833333 + 1 0.1944444444 0.6944444444 + 0.4062821444 0.505787 1 + 0.3726852222 1 0.7708333333 + 0.4083719667 1 0.5347222222 + 0.8373842222 0.427662 1 + 0.8263888889 0.3541666667 1 + 1 0.4097222222 0.9513888889 + 0.9583333333 0.4027777778 1 + 0.9207175556 0.4554397778 1 + 1 0.3368055556 0.9270833333 + 1 0.3229166667 0.8298611111 + 1 0.3885994778 0.4985532222 + 1 0.4593298889 0.4428047778 + 1 0.4561471111 0.3157793333 + 1 0.408404 0.3803047778 + 0.4247685222 1 0.4363425889 + 0.3553240778 1 0.3668981444 + 0.494213 1 0.4066037 + 0.5219907778 1 0.3232703667 + 0.5179397778 1 0.2378472222 + 0.870515 0.5638021111 0 + 0.6735306667 0.4954185556 0 + 0.8091242222 0.5089698889 0 + 0.7338926667 0.5402198889 0 + 1 0.5347222222 0.1597222222 + 0.5769675556 1 0.1765046333 + 0.572338 0.8373842222 0 + 0.5901973333 0.5231963333 0 + 0.8263888889 0.9375 0 + 0.8796777778 0.6416377778 0 + 0.9375 0.8263888889 0 + 0.6458333333 1 0.1736111111 + 0.7430555556 0.9652777778 0 + 0.7430555556 1 0.04861111111 + 0.6736111111 1 0.09027777778 + 0.9433352222 0.6589988889 0 + 0.9652777778 0.7430555556 0 + 1 0.7517361111 0.02256944444 + 1 0.6753472222 0.05729166667 + 0.6528178889 0.6724295556 0 + 0.7280493333 0.6272906667 0 + 0.8124436667 0.6738763333 0 + 0.7152777778 0.8541666667 0 + 0.8125 0.8680555556 0 + 0.6666666667 0.8055555556 0 + 0.70249 0.7398485556 0 + 0.8680555556 0.8125 0 + 1 0.5810185556 0.2222222222 + 1 0.5533693333 0.3157793333 + 1 0.650463 0.2083333333 + 1 0.6892361111 0.1267361111 + 1 0.8107638889 0.06770833333 + 1 0.8923611111 0.04513888889 + 0.9722222222 0.9166666667 0 + 0.9166666667 0.9722222222 0 + 0.8993055556 1 0.05208333333 + 0.8090277778 1 0.1006944444 + 0.3736497778 1 0.6875 + 0.4714667778 1 0.5636574444 + 0.4483186667 1 0.6469907778 + 0.4728008889 1 0.8998842222 + 0.4496527778 1 0.8165508889 + 0.5936374444 0.4652241111 1 + 0.6769707778 0.4374463333 1 + 0.3668981444 0.6446758889 1 + 0.4363425889 0.5752314444 1 + 0.3958333333 0.7453703333 1 + 0.5878504444 0.5501006667 1 + 0.5289352222 0.5964505556 1 + 0.6606706667 0.5922174444 1 + 0.5 0.9027777778 1 + 0.5 0.7939814444 1 + 0.5972222222 1 0.9583333333 + 0.5902777778 0.9513888889 1 + 0.5491897778 1 0.9068286667 + 0.7712994444 0.4808491111 1 + 0.749791 0.5883594444 1 + 0.8060216667 0.5433491111 1 + 0.9513888889 0.5902777778 1 + 1 0.5902777778 0.9513888889 + 0.9137731111 0.5318286667 1 + 1 0.5 0.9027777778 + 1 0.3958333333 0.7453703333 + 1 0.3668981444 0.6446758889 + 1 0.4363425889 0.5752314444 + 1 0.5289352222 0.5964505556 + 0.5098541111 1 0.6956018889 + 0.5121527778 1 0.7818286667 + 0.5792985556 1 0.6469907778 + 0.556713 1 0.4625451111 + 0.5966596667 1 0.5559414444 + 0.5503633333 1 0.5212192222 + 1 0.5 0.7939814444 + 1 0.5495112222 0.4396218889 + 1 0.5713734444 0.5165894444 + 1 0.5958075556 0.3771218889 + 0.6018518889 1 0.3406314444 + 0.619213 1 0.4162487778 + 0.7013888889 1 0.2291666667 + 0.6875 1 0.3009258889 + 0.7951388889 1 0.1979166667 + 1 0.7690972222 0.1371527778 + 0.8066566667 0.7329041111 0 + 1 0.6990741111 0.3125 + 1 0.6720678889 0.3877314444 + 1 0.7708333333 0.2986111111 + 1 0.8020833333 0.2048611111 + 1 0.8993055556 0.1909722222 + 1 0.9479166667 0.1006944444 + 0.9548611111 1 0.1076388889 + 0.9322916667 1 0.1892361111 + 0.8628472222 1 0.2309027778 + 0.5769675556 1 0.8234953333 + 0.6711998889 0.6501414444 1 + 0.5983796667 0.665895 1 + 0.7603202222 0.6462834444 1 + 0.6041666667 0.7453703333 1 + 0.6631944444 0.9270833333 1 + 0.6770833333 0.8298611111 1 + 0.6736111111 1 0.9236111111 + 0.7430555556 1 0.9652777778 + 0.7395833333 0.9756944444 1 + 0.6666666667 1 0.8055555556 + 0.7152777778 1 0.8541666667 + 0.8055555556 0.6944444444 1 + 0.9513888889 0.7569444444 1 + 1 0.7395833333 0.9756944444 + 0.9027777778 0.6805555556 1 + 1 0.6631944444 0.9270833333 + 1 0.7009065556 0.4761445556 + 1 0.6465084444 0.5425025556 + 1 0.6041666667 0.7453703333 + 1 0.6735146667 0.6339377778 + 1 0.6770833333 0.8298611111 + 1 0.5983796667 0.665895 + 0.7056326667 1 0.740162 + 0.6547067778 1 0.677662 + 0.6747685556 1 0.5270062222 + 0.6909722222 1 0.4459876667 + 0.7102623333 1 0.5943286667 + 0.7916666667 1 0.349537 + 0.8732638889 1 0.3107638889 + 0.7777777778 1 0.4189814444 + 1 0.8263888889 0.3541666667 + 1 0.8234953333 0.4230324444 + 1 0.7736303333 0.4906122222 + 1 0.9513888889 0.2569444444 + 0.9774305556 1 0.2482638889 + 0.9427083333 1 0.3246527778 + 1 0.9097222222 0.3263888889 + 0.7604166667 0.8020833333 1 + 0.9236111111 0.8402777778 1 + 0.8229166667 0.9479166667 1 + 0.8298611111 0.8715277778 1 + 1 0.8229166667 0.9479166667 + 0.8263888889 1 0.9375 + 0.8125 1 0.8680555556 + 0.9166666667 1 0.9722222222 + 0.9166666667 0.9722222222 1 + 0.9722222222 0.9166666667 1 + 1 0.9166666667 0.9722222222 + 0.8097993333 1 0.7332175556 + 0.8680555556 1 0.8125 + 1 0.7604166667 0.8020833333 + 1 0.8298611111 0.8715277778 + 1 0.762635 0.6300797778 + 1 0.8055555556 0.6944444444 + 1 0.8083525556 0.5531122222 + 0.8375771111 1 0.6637731111 + 0.8402777778 1 0.4930555556 + 0.788966 1 0.5873842222 + 1 0.9583333333 0.4027777778 + 0.9652777778 1 0.4097222222 + 1 0.9068286667 0.4508102222 + 1 0.8998842222 0.5271991111 + 0.9236111111 1 0.4930555556 + 1 0.9722222222 0.9166666667 + 0.9722222222 1 0.9166666667 + 0.9375 1 0.8263888889 + 1 0.9236111111 0.8402777778 + 1 0.9513888889 0.7569444444 + 0.9652777778 1 0.7430555556 + 1 0.9513888889 0.5902777778 + 0.9583333333 1 0.5833333333 + 0.9236111111 1 0.6597222222 + 1 0.9027777778 0.6805555556 + 0.9166666667 0 0 + 0 0 0.08333333333 + 0 0 0.25 + 0 0.5833333333 1 + 0 0.08333333333 0 + 0.5833333333 1 1 + 0.4166666667 0 0 + 0.08333333333 0 0 + 0.5833333333 0 0 + 1 0 0.08333333333 + 0 0 0.9166666667 + 1 0 0.25 + 1 1 0.25 + 0 0.08333333333 1 + 0.4166666667 1 0 + 0.08333333333 0 1 + 1 0.08333333333 0 + 0 0 0.75 + 0.75 1 0 + 1 0 0.4166666667 + 1 0.25 0 + 1 0.25 1 + 1 0.75 0 + 1 0.5833333333 1 + 0 0 0.4166666667 + 0 0 0.5833333333 + 1 0.4166666667 0 + 0 1 0.25 + 0 1 0.4166666667 + 0.4166666667 0 1 + 1 1 0.4166666667 + 0 0.9166666667 0 + 0 1 0.08333333333 + 0.08333333333 1 0 + 0 0.25 0 + 0.75 1 1 + 1 0 0.5833333333 + 1 0.9166666667 0 + 1 1 0.5833333333 + 1 0 0.75 + 0.5833333333 0 1 + 1 0.75 1 + 1 1 0.75 + 0.25 1 0 + 0 0.4166666667 0 + 0.4166666667 1 1 + 0.75 0 1 + 0.9166666667 1 0 + 0 1 0.75 + 0 0.5833333333 0 + 0 1 0.5833333333 + 0 0.75 0 + 1 0.9166666667 1 + 1 1 0.08333333333 + 0 0.25 1 + 1 0.4166666667 1 + 0 1 0.9166666667 + 0.9166666667 1 1 + 1 0 0.9166666667 + 0 0.9166666667 1 + 0.9166666667 0 1 + 0.08333333333 1 1 + 1 0.08333333333 1 + 1 1 0.9166666667 + 0.5833333333 1 0 + 1 0.5833333333 0 + 0.75 0 0 + 0.25 0 0 + 0 0.75 1 + 0.25 0 1 + 0.25 1 1 + 0 0.4166666667 1 + 0.125 0.9583333333 0 + 0.1979166667 0.9270833333 0 + 0.125 1 0.04166666667 + 0.2239583333 1 0.03645833333 + 0 0.04166666667 0.125 + 0 0.05208333333 0.21875 + 0.03385416667 0 0.2057291667 + 0.06770833333 0 0.1614583333 + 0 0.04166666667 0.04166666667 + 0.06770833333 0 0.078125 + 0.04166666667 0.04166666667 0 + 0 0.04166666667 0.9583333333 + 0.06770833333 0 0.921875 + 0.04166666667 0.04166666667 1 + 0 0.04166666667 0.875 + 0 0.05729166667 0.796875 + 0.06770833333 0 0.8385416667 + 0.03385416667 0 0.7942708333 + 0.9322916667 1 0.1614583333 + 0.9661458333 1 0.2057291667 + 1 0.921875 0.1510416667 + 1 0.9270833333 0.21875 + 0 0.05208333333 0.3020833333 + 0 0.0625 0.375 + 0.03385416667 0 0.2890625 + 0.05208333333 0 0.3645833333 + 0 0.05729166667 0.7135416667 + 0 0.0625 0.625 + 0.03385416667 0 0.7109375 + 0.05208333333 0 0.6354166667 + 0 0.9583333333 0.04166666667 + 0.04166666667 0.9583333333 0 + 0.04166666667 1 0.04166666667 + 0 0.125 0.04166666667 + 0 0.21875 0.05208333333 + 0.04166666667 0.125 0 + 0.0390625 0.21006945 0 + 0.9661458333 1 0.2890625 + 0.9479166667 1 0.3645833333 + 1 0.9270833333 0.3020833333 + 1 0.9375 0.3541666667 + 0 0.3020833333 0.05208333333 + 0 0.3402778333 0.09027778333 + 0 0.3958333333 0.0625 + 0.0390625 0.2934027833 0 + 0.078125 0.3368055 0 + 0.05859375 0.4007523333 0 + 0.28125 0.9270833333 0 + 0.3645833333 0.9270833333 0 + 0.3072916667 1 0.03645833333 + 0.3645833333 1 0.07291666667 + 0 0.4791666667 0.0625 + 0 0.5520833333 0.07291666667 + 0.05859375 0.4840856667 0 + 0.0625 0.5416666667 0 + 0 0.6927083333 0.03645833333 + 0 0.6354166667 0.07291666667 + 0.05729166667 0.7135416667 0 + 0.0625 0.625 0 + 0.9479166667 1 0.4479166667 + 0.9375 1 0.5416666667 + 1 0.9375 0.4375 + 1 0.922743 0.4887153333 + 1 0.9270833333 0.5520833333 + 0.921875 0.1510416667 0 + 0.9270833333 0.21875 0 + 1 0.125 0.04166666667 + 1 0.21006945 0.0390625 + 0 0.125 0.9583333333 + 0 0.1979166667 0.9270833333 + 0.04166666667 0.125 1 + 0.03472221667 0.2083333333 1 + 0.9583333333 1 0.875 + 0.9479166667 1 0.78125 + 1 0.9583333333 0.875 + 1 0.9270833333 0.8020833333 + 0 0.9583333333 0.9583333333 + 0.04166666667 0.9583333333 1 + 0.04166666667 1 0.9583333333 + 0.9479166667 1 0.6979166667 + 0.9375 1 0.625 + 1 0.9270833333 0.71875 + 1 0.9270833333 0.6354166667 + 0.9270833333 0.3020833333 0 + 0.9375 0.3541666667 0 + 1 0.2934027833 0.0390625 + 1 0.3368055 0.078125 + 1 0.4166666667 0.0625 + 0 0.0625 0.5416666667 + 0 0.0625 0.4583333333 + 0.05208333333 0 0.4479166667 + 0.05208333333 0 0.5520833333 + 0 0.7760416667 0.03645833333 + 0 0.875 0.04166666667 + 0.04166666667 0.875 0 + 0.05729166667 0.796875 0 + 0.4479166667 0.9270833333 0 + 0.5043403333 0.9435763333 0 + 0.5625 0.9375 0 + 0.4479166667 1 0.07291666667 + 0.5112846667 1 0.07725695 + 0.5625 1 0.0625 + 0 0.9270833333 0.28125 + 0 0.9375 0.375 + 0.07291666667 1 0.3645833333 + 0.07291666667 1 0.28125 + 0.9375 0.4375 0 + 0.9341725 0.4978298333 0 + 0.9670861667 0.5405816667 0 + 1 0.5 0.0625 + 1 0.5520833333 0.05208333333 + 0 0.9583333333 0.125 + 0 0.9270833333 0.1979166667 + 0.04166666667 1 0.125 + 0.07291666667 1 0.1979166667 + 0.6979166667 0.9479166667 0 + 0.6458333333 0.9375 0 + 0.6458333333 1 0.0625 + 0.6979166667 1 0.07291666667 + 0 0.9479166667 0.78125 + 0 0.9583333333 0.875 + 0.04166666667 1 0.875 + 0.03645833333 1 0.7760416667 + 0 0.9375 0.5416666667 + 0 0.9375 0.4583333333 + 0.07291666667 1 0.4479166667 + 0.07291666667 1 0.5520833333 + 0.9670861667 0.623915 0 + 0.9479166667 0.6979166667 0 + 1 0.6354166667 0.05208333333 + 1 0.7109375 0.03385416667 + 0 0.9479166667 0.6979166667 + 0 0.9375 0.625 + 0.03645833333 1 0.6927083333 + 0.07291666667 1 0.6354166667 + 0 0.875 0.9583333333 + 0 0.78125 0.9479166667 + 0.04166666667 0.875 1 + 0.03645833333 0.7760416667 1 + 0.9583333333 0.875 0 + 0.9479166667 0.78125 0 + 1 0.7942708333 0.03385416667 + 1 0.8385416667 0.06770833333 + 0 0.28125 0.9270833333 + 0 0.3645833333 0.9270833333 + 0.03472221667 0.2916666667 1 + 0.06944445 0.3333333333 1 + 0.0625 0.3958333333 1 + 0 0.4479166667 0.9270833333 + 0 0.5625 0.9375 + 0 0.5043403333 0.9435763333 + 0.0625 0.4791666667 1 + 0.07291666667 0.5520833333 1 + 0.78125 0.9479166667 0 + 0.875 0.9583333333 0 + 0.78125 1 0.07291666667 + 0.8489583333 1 0.078125 + 0 0.6979166667 0.9479166667 + 0 0.6458333333 0.9375 + 0.03645833333 0.6927083333 1 + 0.07291666667 0.6354166667 1 + 0.9583333333 0.9583333333 0 + 0.9322916667 1 0.078125 + 1 0.921875 0.06770833333 + 0.125 0.9583333333 1 + 0.1979166667 0.9270833333 1 + 0.125 1 0.9583333333 + 0.1979166667 1 0.9270833333 + 0.921875 0.1510416667 1 + 0.9270833333 0.21875 1 + 1 0.125 0.9583333333 + 1 0.2239583333 0.9635416667 + 0.21875 0 0.07291666667 + 0.1510416667 0 0.078125 + 0.125 0.04166666667 0 + 0.21875 0.05208333333 0 + 0.1510416667 0 0.921875 + 0.21875 0 0.9270833333 + 0.125 0.04166666667 1 + 0.21006945 0.0390625 1 + 0.5295138333 0 0.04513888333 + 0.4791666667 0 0.0625 + 0.5520833333 0.05208333333 0 + 0.4791666667 0.0625 0 + 0.28125 0.9270833333 1 + 0.3645833333 0.9270833333 1 + 0.28125 1 0.9270833333 + 0.3645833333 1 0.9270833333 + 0.3020833333 0 0.07291666667 + 0.3958333333 0 0.0625 + 0.3020833333 0.05208333333 0 + 0.3958333333 0.0625 0 + 0.3402778333 0.09027778333 0 + 0.3020833333 0 0.9270833333 + 0.3541666667 0 0.9375 + 0.2934027833 0.0390625 1 + 0.4166666667 0.0625 1 + 0.3368055 0.078125 1 + 0.9270833333 0.3020833333 1 + 0.9375 0.3541666667 1 + 1 0.3072916667 0.9635416667 + 1 0.3645833333 0.9270833333 + 0.4375 0 0.9375 + 0.4956596667 0 0.9435763333 + 0.5520833333 0 0.9270833333 + 0.5 0.0625 1 + 0.5520833333 0.05208333333 1 + 0.71875 0 0.9270833333 + 0.6354166667 0 0.9270833333 + 0.7109375 0.03385416667 1 + 0.6354166667 0.05208333333 1 + 0.4479166667 0.9270833333 1 + 0.5520833333 0.9270833333 1 + 0.4479166667 1 0.9270833333 + 0.5112846667 1 0.922743 + 0.5625 1 0.9375 + 0.9583333333 0 0.9583333333 + 0.921875 0.06770833333 1 + 1 0.04166666667 0.9583333333 + 0.9375 0.4375 1 + 0.9435763333 0.4956596667 1 + 0.9270833333 0.5520833333 1 + 1 0.4479166667 0.9270833333 + 1 0.5520833333 0.9270833333 + 0.6128471667 0 0.04513888333 + 0.6979166667 0 0.05208333333 + 0.7109375 0.03385416667 0 + 0.6354166667 0.05208333333 0 + 0.78125 0 0.05208333333 + 0.875 0 0.04166666667 + 0.7942708333 0.03385416667 0 + 0.8385416667 0.06770833333 0 + 0.6354166667 0.9270833333 1 + 0.6927083333 0.9635416667 1 + 0.6458333333 1 0.9375 + 0.6979166667 1 0.9479166667 + 0.9583333333 0 0.125 + 0.9479166667 0 0.21875 + 1 0.05208333333 0.21875 + 1 0.04166666667 0.125 + 0.9583333333 0 0.04166666667 + 0.921875 0.06770833333 0 + 1 0.04166666667 0.04166666667 + 0.9270833333 0.6354166667 1 + 0.9270833333 0.71875 1 + 1 0.6354166667 0.9270833333 + 1 0.6927083333 0.9635416667 + 0.9479166667 0 0.3020833333 + 0.9375 0 0.3541666667 + 1 0.05208333333 0.3020833333 + 1 0.0625 0.3541666667 + 0.9270833333 0.8020833333 1 + 0.9583333333 0.875 1 + 1 0.7760416667 0.9635416667 + 1 0.875 0.9583333333 + 0.7760416667 0.9635416667 1 + 0.875 0.9583333333 1 + 0.78125 1 0.9479166667 + 0.875 1 0.9583333333 + 0.9583333333 0.9583333333 1 + 0.9583333333 1 0.9583333333 + 1 0.9583333333 0.9583333333 + 0.9375 0 0.4375 + 0.9435763333 0 0.4956596667 + 0.9270833333 0 0.5520833333 + 1 0.0625 0.4375 + 1 0.07725695 0.4887153333 + 1 0.07291666667 0.5520833333 + 0.9583333333 0 0.875 + 0.9635416667 0 0.7760416667 + 1 0.04166666667 0.875 + 1 0.07291666667 0.8020833333 + 0.9635416667 0 0.6927083333 + 0.9270833333 0 0.6354166667 + 1 0.07291666667 0.6354166667 + 1 0.07291666667 0.71875 + 0.875 0 0.9583333333 + 0.8020833333 0 0.9270833333 + 0.7942708333 0.03385416667 1 + 0.8385416667 0.06770833333 1 + +2690 + 4 1433 2039 1432 120 + 4 2049 1586 348 1585 + 5 2078 1433 120 336 1575 + 6 2079 1575 336 347 348 1586 + 6 1432 2080 1584 347 336 120 + 5 1584 2081 1585 348 347 + 4 1391 2007 1390 75 + 4 2008 1387 72 1386 + 6 1388 2082 1391 75 74 73 + 5 1387 2083 1388 73 72 + 6 2084 1386 72 73 74 1389 + 5 2085 1389 74 75 1390 + 4 2010 1393 76 1392 + 4 2013 1395 78 1394 + 6 1391 2086 1392 76 77 75 + 6 2087 1390 75 77 78 1395 + 6 1393 2088 1394 78 77 76 + 5 1380 2016 1383 70 68 + 4 2019 1403 83 1402 + 4 2021 1382 69 1381 + 5 2089 1380 68 83 1403 + 5 2090 1381 69 70 1383 + 7 2091 1402 83 68 70 69 1382 + 4 1385 2023 1384 71 + 6 1380 2092 1405 86 84 68 + 6 2093 1385 71 90 86 1405 + 6 2094 1383 70 88 92 1407 + 6 1384 2095 1407 92 90 71 + 4 70 68 84 88 + 5 84 86 90 92 88 + 4 1967 2018 1966 1319 + 4 2059 1929 1228 1928 + 6 2096 1930 1229 1227 1228 1929 + 5 1930 2097 1967 1319 1229 + 5 1927 2098 1928 1228 1227 + 6 2099 1927 1227 1229 1319 1966 + 4 2030 1422 106 1421 + 6 2100 1387 72 101 104 1418 + 5 2101 1418 104 106 1422 + 5 1386 2102 1415 101 72 + 6 1415 2103 1421 106 104 101 + 4 2031 1420 105 1419 + 6 1385 2104 1416 102 103 71 + 5 1416 2105 1419 105 102 + 5 2106 1384 71 103 1417 + 6 1420 2107 1417 103 102 105 + 4 2037 1429 117 1428 + 4 2038 1431 118 1430 + 6 1429 2108 1430 118 119 117 + 6 2109 1428 117 119 120 1433 + 6 1431 2110 1432 120 119 118 + 4 2040 1397 79 1396 + 6 1392 2111 1438 125 123 76 + 6 2112 1396 79 127 125 1438 + 6 2113 1393 76 123 128 1439 + 6 1397 2114 1439 128 127 79 + 4 123 125 127 128 + 4 1992 2036 1991 1365 + 5 1967 2115 1968 1320 1319 + 6 1968 2116 1992 1365 1321 1320 + 6 2117 1966 1319 1320 1321 1969 + 5 2118 1969 1321 1365 1991 + 4 2050 1449 141 1448 + 6 1396 2119 1441 132 131 79 + 5 1441 2120 1450 142 132 + 6 2121 1448 141 143 142 1450 + 5 2122 1397 79 131 1440 + 7 2123 1440 131 132 142 143 1451 + 5 1449 2124 1451 143 141 + 4 2020 1623 434 1622 + 5 2125 1586 348 350 1588 + 6 2126 1588 350 351 434 1623 + 6 1585 2127 1589 351 350 348 + 5 1589 2128 1622 434 351 + 4 2055 1477 181 1476 + 6 1448 2129 1473 178 179 141 + 5 1473 2130 1476 181 178 + 5 2131 1449 141 179 1474 + 6 1477 2132 1474 179 178 181 + 4 1453 2057 1452 144 + 6 2133 1453 144 177 180 1475 + 5 2134 1475 180 181 1476 + 5 1452 2135 1472 177 144 + 6 1472 2136 1477 181 180 177 + 4 2003 2044 2002 1377 + 6 1992 2137 1995 1370 1368 1365 + 6 2138 2003 1377 1369 1370 1995 + 6 2139 1991 1365 1368 1366 1993 + 5 2140 1993 1366 1367 1994 + 6 2141 1994 1367 1369 1377 2002 + 5 1367 1366 1368 1370 1369 + 4 2026 1594 356 1593 + 4 1558 2022 1557 307 + 6 1557 2142 1727 639 635 307 + 6 2143 1593 356 642 639 1727 + 6 2144 1558 307 635 640 1728 + 6 1594 2145 1728 640 642 356 + 4 635 639 642 640 + 4 1483 2060 1482 185 + 6 2146 1403 83 87 85 1404 + 6 2147 1404 85 91 185 1482 + 6 1402 2148 1408 93 87 83 + 6 2149 1483 185 91 93 1408 + 4 85 87 93 91 + 4 2048 2001 1376 2000 + 4 1997 2069 1996 1372 + 6 2150 1997 1372 1373 1374 1998 + 6 2001 2151 1998 1374 1371 1376 + 6 1996 2152 1999 1375 1373 1372 + 6 2153 2000 1376 1371 1375 1999 + 4 1371 1374 1373 1375 + 4 1486 2062 1485 187 + 4 1488 2065 1487 188 + 4 1490 2067 1489 190 + 6 1485 2154 1488 188 189 187 + 6 1487 2155 1490 190 189 188 + 6 2156 1486 187 189 190 1489 + 6 2157 2001 1376 1379 1378 2004 + 5 2003 2158 2004 1378 1377 + 5 2000 2159 2005 1379 1376 + 6 2160 2002 1377 1378 1379 2005 + 4 1756 2032 1755 726 + 6 1593 2161 1624 435 436 356 + 6 1624 2162 1756 726 727 435 + 5 2163 1594 356 436 1625 + 6 1757 2164 1625 436 435 727 + 5 1755 2165 1757 727 726 + 6 1419 2166 1514 240 241 105 + 6 2167 1422 106 233 240 1514 + 6 1421 2168 1511 229 233 106 + 6 2169 1420 105 241 229 1511 + 4 233 229 241 240 + 6 1453 2170 1573 332 330 144 + 6 2171 1429 117 333 332 1573 + 6 1428 2172 1574 334 333 117 + 6 2173 1452 144 330 334 1574 + 4 330 332 333 334 + 4 1783 2070 1782 803 + 5 2174 1623 434 734 1761 + 6 2175 1761 734 737 802 1781 + 6 1782 2176 1781 802 801 803 + 6 1622 2177 1763 737 734 434 + 6 1763 2178 1780 801 802 737 + 5 1780 2179 1783 803 801 + 4 1581 2033 1580 342 + 4 2034 1578 339 1577 + 6 2180 1579 340 343 342 1580 + 5 2181 1577 339 340 1579 + 6 1578 2182 1582 343 340 339 + 5 2183 1581 342 343 1582 + 4 2071 1788 807 1787 + 5 1756 2184 1758 728 726 + 5 1758 2185 1776 796 728 + 6 1776 2186 1787 807 808 796 + 7 2187 1755 726 728 796 808 1789 + 5 1788 2188 1789 808 807 + 5 1430 2189 1569 324 118 + 6 1569 2190 1580 342 344 324 + 6 2191 1431 118 324 344 1583 + 5 1581 2192 1583 344 342 + 4 1853 2024 1852 1034 + 6 2193 1784 804 1035 1034 1852 + 5 2194 1782 803 804 1784 + 6 1783 2195 1854 1035 804 803 + 5 2196 1853 1034 1035 1854 + 4 1627 2054 1626 437 + 6 2197 1484 186 438 437 1626 + 5 1484 2198 1485 187 186 + 6 2199 1628 438 186 187 1486 + 5 2200 1627 437 438 1628 + 4 2056 1631 440 1630 + 5 1629 2201 1630 440 439 + 6 1577 2202 1629 439 441 339 + 5 2203 1578 339 441 1632 + 6 2204 1632 441 439 440 1631 + 4 2028 1857 1039 1856 + 6 1787 2205 1855 1038 1042 807 + 5 1855 2206 1856 1039 1038 + 5 2207 1788 807 1042 1858 + 6 2208 1858 1042 1038 1039 1857 + 6 2209 1626 437 446 447 1636 + 6 1630 2210 1636 447 443 440 + 6 1627 2211 1635 445 446 437 + 6 2212 1631 440 443 445 1635 + 4 445 443 447 446 + 4 1652 2074 1651 479 + 6 1488 2213 1648 473 464 188 + 6 1648 2214 1652 479 477 473 + 6 2215 1487 188 464 481 1654 + 6 2216 1654 481 477 479 1651 + 4 464 473 477 481 + 4 1873 2043 1872 1062 + 6 1850 2217 1873 1062 1060 1031 + 6 2218 1850 1031 1043 1039 1856 + 6 2219 1857 1039 1043 1061 1871 + 6 1872 2220 1871 1061 1060 1062 + 4 1043 1031 1060 1061 + 4 1656 2077 1655 482 + 5 2221 1482 185 191 1491 + 7 2222 1491 191 192 485 482 1655 + 6 1483 2223 1492 192 191 185 + 5 1492 2224 1658 485 192 + 5 2225 1656 482 485 1658 + 4 1661 2009 1660 487 + 5 2226 1655 482 484 1657 + 5 1660 2227 1662 488 487 + 6 2228 1657 484 486 488 1662 + 6 1656 2229 1659 486 484 482 + 6 1659 2230 1661 487 488 486 + 4 1875 2053 1874 1065 + 6 1848 2231 1852 1034 1032 1029 + 6 2232 1848 1029 1064 1065 1874 + 6 2233 1876 1067 1032 1034 1853 + 6 1876 2234 1875 1065 1064 1067 + 4 1029 1032 1067 1064 + 5 1652 2235 1653 480 479 + 6 1653 2236 1660 487 490 480 + 6 2237 1651 479 480 490 1663 + 5 1661 2238 1663 490 487 + 6 1873 2239 1874 1065 1063 1062 + 6 2240 1929 1228 1063 1065 1875 + 6 2241 1872 1062 1063 1228 1928 + 4 1671 2076 1670 500 + 5 1490 2242 1669 499 190 + 6 2243 1671 500 496 499 1669 + 6 2244 1489 190 499 496 1667 + 5 2245 1667 496 500 1670 + 4 2027 1718 613 1717 + 4 1537 2068 1536 277 + 6 2246 1537 277 564 589 1712 + 6 2247 1712 589 612 613 1718 + 6 1536 2248 1716 611 564 277 + 6 1716 2249 1717 613 612 611 + 4 589 564 611 612 + 4 2073 1401 82 1400 + 5 2250 1399 81 82 1401 + 6 2251 1395 78 80 81 1399 + 5 1394 2252 1398 80 78 + 6 1398 2253 1400 82 81 80 + 4 1411 2075 1410 96 + 6 1381 2254 1409 95 94 69 + 6 1409 2255 1411 96 98 95 + 6 2256 1382 69 94 97 1412 + 6 1410 2257 1412 97 98 96 + 4 94 95 98 97 + 4 1457 2012 1456 147 + 4 2014 1437 122 1436 + 6 1437 2258 1455 146 145 122 + 5 1455 2259 1457 147 146 + 5 2260 1436 122 145 1454 + 6 2261 1454 145 146 147 1456 + 4 1812 2051 1811 876 + 5 1671 2262 1809 873 500 + 6 2263 1812 876 871 873 1809 + 6 2264 1670 500 873 871 1808 + 5 2265 1808 871 876 1811 + 6 2266 1401 82 165 162 1465 + 6 1457 2267 1465 162 164 147 + 6 1400 2268 1471 176 165 82 + 6 2269 1456 147 164 174 1469 + 5 2270 1469 174 176 1471 + 5 164 162 165 176 174 + 4 1480 2035 1479 183 + 6 1411 2271 1499 210 211 96 + 6 2272 1480 183 209 210 1499 + 5 2273 1410 96 211 1500 + 5 1479 2274 1498 209 183 + 6 1498 2275 1500 211 210 209 + 4 2061 1827 938 1826 + 5 2276 1718 613 614 1719 + 6 2277 1719 614 940 938 1827 + 6 1717 2278 1829 940 614 613 + 5 2279 1826 938 940 1829 + 4 2046 1521 248 1520 + 5 1480 2280 1481 184 183 + 6 1481 2281 1522 249 245 184 + 5 2282 1520 248 249 1522 + 6 2283 1479 183 184 245 1516 + 6 2284 1516 245 249 248 1521 + 4 2052 1518 246 1517 + 6 2285 1517 246 247 250 1523 + 5 1520 2286 1523 250 248 + 5 1518 2287 1519 247 246 + 6 1519 2288 1521 248 250 247 + 4 1893 2011 1892 1113 + 6 1812 2289 1890 1110 1081 876 + 6 1890 2290 1893 1113 1114 1110 + 5 2291 1811 876 1081 1880 + 6 2292 1880 1081 1110 1114 1894 + 5 1892 2293 1894 1114 1113 + 4 2064 1535 275 1534 + 4 2066 1525 251 1524 + 6 1525 2294 1534 275 276 251 + 6 2295 1524 251 276 277 1537 + 6 1535 2296 1536 277 276 275 + 4 1899 2029 1898 1126 + 5 2297 1827 938 939 1828 + 6 2298 1828 939 1128 1127 1900 + 5 1898 2299 1900 1127 1126 + 6 1826 2300 1901 1128 939 938 + 6 2301 1899 1126 1127 1128 1901 + 4 2072 1435 121 1434 + 6 2302 1437 122 290 285 1544 + 6 1435 2303 1544 285 289 121 + 6 2304 1434 121 289 283 1543 + 6 1436 2305 1543 283 290 122 + 4 283 289 285 290 + 4 1552 2006 1551 299 + 6 2306 1435 121 294 295 1549 + 6 2307 1549 295 300 299 1551 + 6 1434 2308 1553 301 294 121 + 6 2309 1552 299 300 301 1553 + 4 295 294 301 300 + 4 1941 2041 1940 1255 + 5 1893 2310 1937 1251 1113 + 6 1937 2311 1941 1255 1253 1251 + 6 2312 1892 1113 1251 1253 1939 + 5 2313 1939 1253 1255 1940 + 4 1555 2015 1554 304 + 4 1539 2017 1538 278 + 6 1550 2314 1555 304 302 296 + 6 1538 2315 1550 296 298 278 + 6 2316 1539 278 298 306 1556 + 6 2317 1556 306 302 304 1554 + 4 298 296 302 306 + 6 2318 1551 299 305 304 1555 + 6 1552 2319 1557 307 305 299 + 6 2320 1554 304 305 307 1558 + 4 1946 2047 1945 1267 + 6 2321 1898 1126 1269 1268 1947 + 5 1945 2322 1947 1268 1267 + 5 1899 2323 1948 1269 1126 + 6 2324 1946 1267 1268 1269 1948 + 4 1562 2025 1561 310 + 5 2325 1538 278 308 1559 + 6 2326 1559 308 309 310 1561 + 6 1539 2327 1560 309 308 278 + 5 1560 2328 1562 310 309 + 4 1980 2058 1979 1343 + 7 1971 2329 1945 1267 1266 1326 1325 + 6 2330 1971 1325 1335 1343 1979 + 6 2331 1974 1336 1266 1267 1946 + 7 2332 1980 1343 1335 1337 1336 1974 + 4 1326 1266 1336 1337 + 4 1325 1326 1337 1335 + 4 1978 2063 1977 1342 + 6 1941 2333 1972 1327 1329 1255 + 6 1972 2334 1978 1342 1340 1327 + 6 2335 1940 1255 1329 1338 1975 + 6 2336 1975 1338 1340 1342 1977 + 4 1329 1327 1340 1338 + 6 1978 2337 1979 1343 1344 1342 + 6 2338 1977 1342 1344 1372 1997 + 6 1980 2339 1996 1372 1344 1343 + 4 1677 2042 1676 505 + 6 2340 1561 310 502 501 1672 + 6 2341 1672 501 506 504 1675 + 5 2342 1675 504 505 1676 + 5 1562 2343 1673 502 310 + 6 2344 1678 506 501 502 1673 + 6 1678 2345 1677 505 504 506 + 4 2045 1683 510 1682 + 6 1534 2346 1681 509 508 275 + 5 1681 2347 1682 510 509 + 5 2348 1535 275 508 1680 + 6 2349 1680 508 509 510 1683 + 6 2350 1674 503 507 510 1682 + 5 1674 2351 1676 505 503 + 6 2352 1679 507 503 505 1677 + 5 1679 2353 1683 510 507 + 6 2354 1525 251 566 568 1704 + 6 1517 2355 1704 568 570 246 + 6 2356 1518 246 570 567 1703 + 6 1524 2357 1703 567 566 251 + 4 566 567 570 568 + 4 1406 1405 86 89 + 4 1404 1406 89 85 + 4 68 83 87 84 + 5 86 84 87 85 89 + 5 1406 1426 111 112 89 + 4 1426 1425 109 111 + 5 1425 1416 102 114 109 + 5 71 90 110 115 103 + 4 102 103 115 114 + 5 86 89 112 110 90 + 6 111 109 114 115 110 112 + 4 1444 1438 125 136 + 5 1388 1443 135 126 73 + 4 1443 1444 136 135 + 4 74 73 126 124 + 5 75 74 124 129 77 + 4 76 77 129 123 + 7 125 123 129 124 126 135 136 + 5 1442 1441 132 133 134 + 4 1444 1442 134 136 + 4 79 127 130 131 + 4 131 130 133 132 + 6 127 125 136 134 133 130 + 5 1418 1445 137 140 104 + 5 1445 1463 159 160 137 + 5 1463 1443 135 157 159 + 6 73 72 101 149 155 126 + 5 101 104 140 158 149 + 4 135 126 155 157 + 4 140 137 160 158 + 6 155 149 158 160 159 157 + 5 1495 1426 111 193 200 + 5 1491 1495 200 201 191 + 5 91 185 191 201 195 + 6 89 85 91 195 196 112 + 4 111 112 196 193 + 5 193 196 195 201 200 + 5 1504 1425 109 219 218 + 4 1505 1504 218 221 + 4 1506 1505 221 222 + 4 1495 1494 199 200 + 5 1494 1506 222 223 199 + 5 109 111 193 220 219 + 5 193 200 199 223 220 + 6 218 219 220 223 222 221 + 4 1510 1514 240 228 + 5 1504 1510 228 244 218 + 5 105 102 114 232 241 + 5 114 109 219 227 232 + 4 219 218 244 227 + 6 232 227 244 228 240 241 + 5 1510 1447 139 230 228 + 4 1447 1445 137 139 + 5 104 106 233 235 140 + 5 139 137 140 235 230 + 5 228 230 235 233 240 + 5 1505 1564 312 318 221 + 5 1564 1446 138 315 312 + 4 1446 1447 139 138 + 5 138 139 230 319 315 + 5 218 221 318 313 244 + 5 230 228 244 313 319 + 5 312 315 319 313 318 + 4 1565 1564 312 317 + 4 1506 1507 224 222 + 4 1507 1508 225 224 + 5 1508 1565 317 316 225 + 6 221 222 224 225 316 318 + 4 317 312 318 316 + 5 1566 1446 138 320 321 + 4 1565 1567 322 317 + 4 1568 1566 321 323 + 4 1567 1568 323 322 + 3 138 315 320 + 7 315 312 317 322 323 321 320 + 4 1571 1573 332 329 + 5 1475 1572 331 326 180 + 4 1572 1570 325 331 + 4 1570 1571 329 325 + 4 144 177 327 330 + 4 177 180 326 327 + 7 325 329 332 330 327 326 331 + 5 1571 1569 324 328 329 + 4 119 117 333 335 + 5 118 119 335 328 324 + 5 329 328 335 333 332 + 4 1598 1602 373 368 + 5 1602 1463 159 365 373 + 5 1566 1598 368 372 321 + 7 137 139 138 320 360 362 160 + 4 159 160 362 365 + 4 320 321 372 360 + 6 362 360 372 368 373 365 + 5 1442 1602 373 376 134 + 5 1601 1450 142 363 371 + 4 1598 1601 371 368 + 5 132 133 359 363 142 + 4 133 134 376 359 + 6 363 359 376 373 368 371 + 6 134 136 135 157 375 376 + 4 157 159 365 375 + 4 365 373 376 375 + 5 1603 1473 178 383 385 + 5 1597 1603 385 388 367 + 4 1601 1597 367 371 + 4 143 142 363 361 + 5 141 143 361 366 179 + 5 178 179 366 389 383 + 7 361 363 371 367 388 389 366 + 4 385 383 389 388 + 4 1603 1604 386 385 + 5 1604 1572 331 387 386 + 6 181 178 383 384 326 180 + 4 331 326 384 387 + 5 384 383 385 386 387 + 5 1647 1484 186 471 472 + 4 1644 1647 472 466 + 4 1636 1634 444 447 + 5 1634 1644 466 467 444 + 4 186 438 476 471 + 5 438 437 446 465 476 + 5 447 444 467 465 446 + 6 465 467 466 472 471 476 + 4 1647 1650 475 472 + 4 1650 1648 473 475 + 4 188 189 469 464 + 5 187 186 471 469 189 + 6 464 469 471 472 475 473 + 4 1646 1650 475 470 + 4 1644 1646 470 466 + 4 466 470 475 472 + 4 1646 1645 468 470 + 5 1645 1653 480 478 468 + 4 477 478 480 479 + 6 470 468 478 477 473 475 + 5 1685 1494 199 520 512 + 5 1657 1685 512 516 484 + 4 191 192 198 201 + 4 198 192 485 483 + 6 482 484 516 518 483 485 + 7 201 198 483 518 520 199 200 + 4 516 512 520 518 + 5 1687 1507 224 521 515 + 4 1686 1687 515 514 + 4 1685 1686 514 512 + 4 223 199 520 522 + 5 222 223 522 521 224 + 6 512 514 515 521 522 520 + 5 1695 1508 225 538 543 + 5 1687 1693 537 541 515 + 4 1694 1695 543 540 + 4 1693 1694 540 537 + 5 225 224 521 539 538 + 4 521 515 541 539 + 6 537 540 543 538 539 541 + 5 1692 1567 322 542 536 + 4 1695 1692 536 543 + 4 316 225 538 544 + 5 317 316 544 542 322 + 5 536 542 544 538 543 + 5 1597 1741 684 686 367 + 4 1741 1742 687 684 + 5 1744 1604 386 693 692 + 4 1742 1744 692 687 + 4 388 367 686 689 + 5 386 385 388 689 693 + 6 686 684 687 692 693 689 + 5 1568 1741 684 690 323 + 5 321 323 690 688 372 + 6 367 371 368 372 688 686 + 4 684 686 688 690 + 4 1740 1742 687 680 + 5 1692 1740 680 681 536 + 5 323 322 542 682 690 + 4 542 536 681 682 + 6 681 680 687 684 690 682 + 5 1747 1570 325 695 707 + 4 1745 1747 707 704 + 5 1744 1746 706 703 692 + 4 1746 1745 704 706 + 5 325 331 387 699 695 + 5 387 386 693 698 699 + 4 693 692 703 698 + 7 695 699 698 703 706 704 707 + 5 1747 1579 340 702 707 + 4 324 328 341 344 + 5 340 343 345 697 702 + 5 344 341 345 343 342 + 7 329 325 695 697 345 341 328 + 4 697 695 707 702 + 5 1629 1748 708 705 439 + 5 1748 1633 442 696 708 + 4 1633 1634 444 442 + 5 440 439 705 709 443 + 6 442 444 447 443 709 696 + 4 708 696 709 705 + 4 1745 1748 708 704 + 5 339 340 702 701 441 + 4 439 441 701 705 + 6 701 702 707 704 708 705 + 5 1743 1746 706 700 691 + 4 1740 1743 691 680 + 6 687 680 691 700 703 692 + 3 703 700 706 + 5 1792 1633 442 818 815 + 5 1743 1790 809 817 691 + 4 1790 1792 815 809 + 4 442 696 816 818 + 4 700 691 817 820 + 7 696 708 704 706 700 820 816 + 6 809 815 818 816 820 817 + 5 1791 1649 474 810 813 + 4 1792 1791 813 815 + 4 1649 1645 468 474 + 5 444 442 818 814 467 + 7 466 467 814 810 474 468 470 + 5 813 810 814 818 815 + 5 1791 1693 537 812 813 + 5 1684 1649 474 513 511 + 4 1686 1684 511 514 + 4 513 474 810 811 + 7 511 513 811 822 541 515 514 + 4 537 541 822 812 + 5 811 810 813 812 822 + 5 1694 1790 809 823 540 + 6 536 543 540 823 819 681 + 5 680 681 819 817 691 + 4 809 817 819 823 + 4 540 537 812 823 + 5 815 809 823 812 813 + 6 1684 1662 488 854 855 511 + 4 480 478 489 490 + 6 488 487 490 489 850 854 + 7 468 474 513 851 850 489 478 + 4 513 511 855 851 + 4 850 851 855 854 + 5 484 486 857 858 516 + 4 486 488 854 857 + 6 511 514 512 516 858 855 + 4 854 855 858 857 + 4 1407 1423 107 92 + 4 1424 1409 95 108 + 4 1423 1424 108 107 + 4 69 70 88 94 + 6 88 92 107 108 95 94 + 5 1417 1427 116 115 103 + 5 1427 1423 107 113 116 + 5 92 90 110 113 107 + 4 113 110 115 116 + 6 1389 1458 150 148 124 74 + 5 1460 1415 101 149 152 + 4 1458 1460 152 150 + 4 126 124 148 155 + 5 148 150 152 149 155 + 5 1461 1399 81 154 153 + 4 1462 1461 153 156 + 5 1464 1462 156 166 161 + 4 1465 1464 161 162 + 5 81 82 165 163 154 + 5 153 154 163 166 156 + 5 162 161 166 163 165 + 4 1461 1458 150 153 + 6 77 78 80 168 173 129 + 5 80 81 154 167 168 + 4 168 167 170 173 + 5 124 129 173 170 148 + 6 150 148 170 167 154 153 + 5 1424 1497 206 203 108 + 4 1497 1496 204 206 + 5 1496 1499 210 207 204 + 4 96 98 213 211 + 5 207 210 211 213 215 + 6 98 95 108 203 215 213 + 5 203 206 204 207 215 + 4 1512 1511 229 236 + 5 1460 1513 237 242 152 + 4 1513 1512 236 237 + 4 140 158 231 235 + 5 149 152 242 231 158 + 7 229 233 235 231 242 237 236 + 5 1515 1427 116 238 243 + 4 1512 1515 243 236 + 5 115 114 232 238 116 + 6 229 236 243 238 232 241 + 4 1509 1513 237 226 + 5 1459 1509 226 239 151 + 4 1462 1459 151 156 + 7 152 150 153 156 151 239 242 + 4 226 237 242 239 + 5 1515 1529 264 262 243 + 4 1529 1528 261 264 + 5 1528 1497 206 260 261 + 5 108 107 113 205 203 + 5 113 116 238 234 205 + 6 203 205 234 263 260 206 + 5 234 238 243 262 263 + 5 261 260 263 262 264 + 5 1509 1527 255 256 226 + 5 1527 1529 264 259 255 + 7 237 226 256 258 262 243 236 + 4 256 255 259 258 + 4 258 259 264 262 + 4 1531 1527 255 266 + 5 1459 1526 253 252 151 + 4 1526 1530 265 253 + 4 1530 1531 266 265 + 4 239 151 252 257 + 4 226 239 257 256 + 7 252 253 265 266 255 256 257 + 4 1533 1528 261 269 + 5 1531 1532 268 267 266 + 4 1532 1533 269 268 + 4 259 255 266 267 + 6 264 259 267 268 269 261 + 4 1544 1542 282 285 + 5 1546 1455 146 279 288 + 4 1542 1546 288 282 + 4 145 122 290 284 + 4 146 145 284 279 + 6 279 284 290 285 282 288 + 4 1549 1548 293 295 + 4 1545 1542 282 287 + 5 1548 1545 287 291 293 + 4 289 121 294 297 + 6 282 285 289 297 291 287 + 5 293 291 297 294 295 + 4 1547 1548 293 292 + 4 1550 1547 292 296 + 4 300 299 305 303 + 4 302 303 305 304 + 7 292 293 295 300 303 302 296 + 5 1464 1608 397 394 161 + 4 1608 1609 398 397 + 5 1609 1526 253 399 398 + 5 151 156 166 254 252 + 5 166 161 394 400 254 + 5 253 252 254 400 399 + 5 394 397 398 399 400 + 5 1546 1608 397 395 288 + 5 147 146 279 286 164 + 6 161 162 164 286 403 394 + 5 286 279 288 395 403 + 4 397 394 403 395 + 4 1607 1609 398 396 + 5 1541 1607 396 402 281 + 4 1545 1541 281 287 + 6 287 281 402 395 288 282 + 5 397 395 402 396 398 + 5 1638 1496 204 461 455 + 4 1639 1638 455 457 + 4 1637 1639 457 448 + 5 1533 1637 448 454 269 + 5 204 206 260 450 461 + 5 260 261 269 454 450 + 6 454 448 457 455 461 450 + 5 1638 1481 184 449 455 + 5 184 183 209 452 449 + 5 210 207 451 452 209 + 4 207 204 461 451 + 5 449 452 451 461 455 + 5 1640 1522 249 456 459 + 4 1639 1640 459 457 + 4 245 184 449 458 + 4 249 245 458 456 + 6 449 455 457 459 456 458 + 4 1696 1701 562 556 + 5 1701 1530 265 563 562 + 5 1607 1697 557 554 396 + 4 1697 1696 556 557 + 5 265 253 399 560 563 + 5 398 396 554 560 399 + 6 554 557 556 562 563 560 + 4 1700 1701 562 561 + 4 1696 1699 559 556 + 4 1698 1700 561 558 + 4 1699 1698 558 559 + 5 556 559 558 561 562 + 4 1704 1705 571 568 + 5 1705 1681 509 569 571 + 4 276 251 566 573 + 5 275 276 573 574 508 + 4 509 508 574 569 + 6 566 568 571 569 574 573 + 5 1523 1708 579 588 250 + 4 1706 1705 571 572 + 5 1708 1706 572 581 579 + 4 246 247 576 570 + 5 247 250 588 577 576 + 7 568 570 576 577 581 572 571 + 4 581 577 588 579 + 5 1640 1709 580 585 459 + 4 1709 1708 579 580 + 6 248 249 456 586 588 250 + 4 456 459 585 586 + 5 580 579 588 586 585 + 4 1637 1641 460 448 + 5 1641 1710 582 583 460 + 4 1710 1709 580 582 + 6 457 448 460 583 585 459 + 4 582 580 585 583 + 5 1714 1532 268 596 592 + 5 1700 1714 592 600 561 + 6 266 265 563 594 597 267 + 4 268 267 597 596 + 5 562 561 600 594 563 + 5 592 596 597 594 600 + 5 1714 1641 460 595 592 + 5 269 268 596 602 454 + 5 448 454 602 595 460 + 4 592 595 602 596 + 5 1541 1720 615 629 281 + 4 1720 1722 617 615 + 5 1722 1697 557 628 617 + 4 402 281 629 619 + 5 396 402 619 623 554 + 4 557 554 623 628 + 6 615 617 628 623 619 629 + 5 1547 1724 625 622 292 + 4 1724 1720 615 625 + 5 281 287 291 618 629 + 5 291 293 292 622 618 + 5 625 615 629 618 622 + 5 1559 1724 625 626 308 + 5 298 278 308 626 630 + 5 292 296 298 630 622 + 4 625 622 630 626 + 5 1732 1722 617 655 657 + 5 1672 1732 657 647 501 + 4 308 309 624 626 + 6 309 310 502 648 654 624 + 4 502 501 647 648 + 7 617 615 625 626 624 654 655 + 5 648 647 657 655 654 + 5 1731 1699 559 656 651 + 4 1732 1731 651 657 + 6 556 557 628 653 656 559 + 4 628 617 655 653 + 5 651 656 653 655 657 + 5 1733 1710 582 662 658 + 5 1698 1733 658 670 558 + 4 583 460 595 593 + 5 561 558 670 664 600 + 5 582 583 593 661 662 + 6 595 592 600 664 661 593 + 5 658 662 661 664 670 + 5 1706 1734 660 668 572 + 5 1734 1674 503 665 660 + 4 503 507 659 665 + 6 507 510 509 569 663 659 + 5 569 571 572 668 663 + 5 659 663 668 660 665 + 4 1733 1735 667 658 + 4 1735 1734 660 667 + 4 572 581 666 668 + 6 579 580 582 662 666 581 + 6 662 658 667 660 668 666 + 5 1731 1736 671 673 651 + 4 1736 1735 667 671 + 5 558 559 656 669 670 + 4 656 651 673 669 + 6 667 658 670 669 673 671 + 5 1675 1736 671 672 504 + 4 501 506 652 647 + 5 506 504 672 674 652 + 6 647 652 674 673 651 657 + 4 672 671 673 674 + 5 505 503 665 672 504 + 5 665 660 667 671 672 + 4 1439 1468 171 128 + 4 1466 1398 80 168 + 5 1468 1466 168 173 171 + 5 123 128 171 173 129 + 5 1440 1467 169 130 131 + 4 1467 1468 171 169 + 5 128 127 130 169 171 + 6 1466 1470 175 172 167 168 + 4 1470 1471 176 175 + 4 163 154 167 172 + 5 165 163 172 175 176 + 4 1576 1574 334 337 + 5 1575 1576 337 338 336 + 5 119 120 336 338 335 + 5 334 333 335 338 337 + 4 1543 1591 353 283 + 4 1590 1553 301 352 + 5 1591 1590 352 354 353 + 5 289 283 353 354 297 + 5 294 297 354 352 301 + 5 1454 1540 280 284 145 + 4 1540 1592 355 280 + 4 1592 1591 353 355 + 6 284 280 355 353 283 290 + 5 1451 1599 369 361 143 + 5 1595 1467 169 374 357 + 4 1599 1596 364 369 + 4 1596 1595 357 364 + 5 130 133 359 374 169 + 7 364 357 374 359 363 361 369 + 5 1474 1600 370 366 179 + 4 1600 1599 369 370 + 4 361 366 370 369 + 5 1606 1472 177 327 393 + 4 1576 1605 391 337 + 4 1605 1606 393 391 + 6 327 330 334 337 391 393 + 4 1469 1478 182 174 + 5 1478 1610 406 407 182 + 5 1610 1540 280 404 406 + 6 164 174 182 407 408 286 + 6 284 279 286 408 404 280 + 4 406 404 408 407 + 5 1612 1470 175 415 417 + 5 1595 1612 417 416 357 + 6 171 169 374 358 170 173 + 6 167 170 358 412 418 172 + 4 175 172 418 415 + 5 374 357 416 412 358 + 5 412 416 417 415 418 + 4 1612 1611 411 417 + 5 1611 1478 182 410 411 + 6 174 176 175 415 410 182 + 4 411 410 415 417 + 5 1615 1600 370 390 426 + 5 1606 1614 425 392 393 + 4 1614 1615 426 425 + 5 326 327 393 392 384 + 4 370 366 389 390 + 7 383 384 392 425 426 390 389 + 4 1613 1596 364 423 + 5 1616 1613 423 422 427 + 4 1615 1616 427 426 + 6 364 369 370 390 422 423 + 4 422 390 426 427 + 4 1617 1611 411 428 + 5 1613 1618 430 424 423 + 4 1618 1617 428 430 + 5 357 364 423 424 416 + 6 411 417 416 424 430 428 + 4 1619 1610 406 431 + 5 1617 1619 431 429 428 + 4 407 182 410 413 + 5 406 407 413 429 431 + 5 410 411 428 429 413 + 5 1620 1592 355 405 432 + 4 1619 1621 433 431 + 4 1621 1620 432 433 + 4 355 280 404 405 + 6 405 404 406 431 433 432 + 5 1590 1726 638 633 352 + 4 1726 1727 639 638 + 5 305 303 644 635 307 + 6 300 301 352 633 644 303 + 5 633 638 639 635 644 + 5 1588 1749 715 711 350 + 5 1749 1605 391 713 715 + 5 338 336 347 349 346 + 4 346 349 714 719 + 6 347 348 350 711 714 349 + 6 337 338 346 719 713 391 + 5 714 711 715 713 719 + 5 1759 1749 715 729 731 + 4 1762 1759 731 736 + 5 1761 1762 736 735 734 + 4 350 351 712 711 + 6 351 434 734 735 733 712 + 5 711 712 733 729 715 + 5 731 729 733 735 736 + 5 1766 1726 638 749 742 + 5 1620 1768 750 743 432 + 4 1768 1766 742 750 + 6 354 353 355 405 637 645 + 4 352 354 645 633 + 5 405 432 743 746 637 + 6 638 633 645 637 746 749 + 5 742 749 746 743 750 + 5 1767 1624 435 740 745 + 4 1766 1767 745 742 + 4 436 356 642 634 + 5 435 436 634 744 740 + 6 634 642 639 638 749 744 + 5 740 744 749 742 745 + 4 1767 1765 741 745 + 5 1765 1758 728 748 741 + 4 727 435 740 751 + 5 726 727 751 748 728 + 5 740 745 741 748 751 + 5 1769 1614 425 768 773 + 5 1759 1769 773 776 731 + 5 393 391 713 710 392 + 5 425 392 710 775 768 + 6 710 713 715 729 774 775 + 4 729 731 776 774 + 5 773 768 775 774 776 + 5 1616 1770 787 753 427 + 5 1773 1618 430 780 792 + 5 1770 1773 792 791 787 + 5 423 422 759 756 424 + 4 422 427 753 759 + 5 430 424 756 783 780 + 6 759 753 787 791 783 756 + 4 780 783 791 792 + 4 1769 1772 790 773 + 5 1772 1770 787 789 790 + 6 426 425 768 770 753 427 + 4 753 770 789 787 + 5 770 768 773 790 789 + 5 1771 1621 433 785 788 + 4 1773 1771 788 792 + 5 431 429 784 785 433 + 5 429 428 430 780 784 + 5 784 780 792 788 785 + 4 1775 1768 750 794 + 4 1771 1774 793 788 + 5 1774 1775 794 795 793 + 5 432 433 785 781 743 + 5 750 743 781 795 794 + 5 781 785 788 793 795 + 4 1762 1779 799 736 + 4 1777 1772 790 797 + 4 1778 1777 797 798 + 5 1779 1778 798 800 799 + 5 731 736 799 800 776 + 6 773 776 800 798 797 790 + 5 1842 1765 741 996 992 + 5 1775 1841 989 988 794 + 4 1841 1843 994 989 + 4 1843 1842 992 994 + 7 741 745 742 750 794 988 996 + 5 988 989 994 992 996 + 5 1840 1776 796 991 987 + 4 1842 1840 987 992 + 5 728 748 986 991 796 + 4 748 741 996 986 + 5 991 986 996 992 987 + 5 1846 1779 799 1005 1001 + 5 1781 1846 1001 1006 802 + 4 735 734 737 739 + 5 739 737 802 1006 1002 + 6 736 735 739 1002 1005 799 + 4 1001 1005 1002 1006 + 5 1847 1774 793 1010 1013 + 5 1777 1847 1013 1018 797 + 5 787 789 1027 1028 791 + 5 789 790 797 1018 1027 + 6 788 792 791 1028 1010 793 + 5 1013 1010 1028 1027 1018 + 5 1847 1841 989 1014 1013 + 5 794 795 1012 1022 988 + 4 795 793 1010 1012 + 4 989 988 1022 1014 + 5 1012 1010 1013 1014 1022 + 4 1840 1849 1030 987 + 5 1849 1855 1038 1040 1030 + 4 808 796 991 993 + 5 807 808 993 1041 1042 + 4 1040 1038 1042 1041 + 6 991 987 1030 1040 1041 993 + 4 1860 1843 994 1047 + 5 1778 1859 1044 1017 798 + 5 1859 1860 1047 1046 1044 + 4 797 798 1017 1018 + 5 994 989 1014 1046 1047 + 6 1014 1013 1018 1017 1044 1046 + 4 1861 1849 1030 1048 + 4 1860 1861 1048 1047 + 6 987 992 994 1047 1048 1030 + 4 1846 1864 1052 1001 + 5 1865 1859 1044 1045 1053 + 4 1864 1865 1053 1052 + 4 800 799 1005 1009 + 5 798 800 1009 1019 1017 + 7 1005 1001 1052 1053 1045 1019 1009 + 4 1017 1019 1045 1044 + 5 1862 1784 804 1000 1049 + 4 1848 1863 1050 1029 + 5 1863 1862 1049 1051 1050 + 4 1000 804 1035 1037 + 5 1034 1032 1036 1037 1035 + 5 1000 1037 1036 1051 1049 + 5 1032 1029 1050 1051 1036 + 4 1862 1864 1052 1049 + 4 802 801 1003 1006 + 5 801 803 804 1000 1003 + 6 1003 1000 1049 1052 1001 1006 + 4 1850 1866 1054 1031 + 4 1866 1863 1050 1054 + 4 1065 1063 1066 1064 + 4 1062 1060 1066 1063 + 7 1050 1029 1064 1066 1060 1031 1054 + 5 1861 1922 1205 1206 1048 + 5 1922 1866 1054 1209 1205 + 6 1039 1038 1040 1204 1219 1043 + 5 1040 1030 1048 1206 1204 + 5 1031 1043 1219 1209 1054 + 5 1204 1206 1205 1209 1219 + 5 1865 1922 1205 1214 1053 + 5 1047 1046 1213 1206 1048 + 4 1045 1053 1214 1200 + 5 1044 1045 1200 1213 1046 + 5 1213 1200 1214 1205 1206 + 6 1049 1051 1195 1214 1053 1052 + 5 1051 1050 1054 1209 1195 + 4 1195 1209 1205 1214 + 4 1413 1408 93 99 + 4 1412 1414 100 97 + 4 1414 1413 99 100 + 8 87 84 88 94 97 100 99 93 + 5 1413 1493 194 197 99 + 5 1493 1492 192 198 194 + 5 91 93 99 197 195 + 5 197 194 198 201 195 + 4 1501 1414 100 214 + 5 1500 1501 214 213 211 + 5 97 98 213 214 100 + 4 1502 1493 194 216 + 5 1501 1503 217 208 214 + 4 1503 1502 216 217 + 5 99 100 214 208 197 + 5 194 197 208 217 216 + 5 1643 1498 209 452 463 + 5 1516 1642 462 458 245 + 4 1642 1643 463 462 + 5 452 449 458 462 463 + 4 1502 1665 492 216 + 5 1664 1658 485 483 491 + 4 1665 1664 491 492 + 6 198 194 216 492 491 483 + 4 1654 1668 498 481 + 5 1668 1669 499 497 498 + 5 190 189 469 497 499 + 5 469 464 481 498 497 + 5 1688 1503 217 523 524 + 5 1643 1688 524 525 463 + 5 212 208 214 213 215 + 5 208 212 531 523 217 + 6 215 207 451 530 531 212 + 5 451 452 463 525 530 + 5 524 523 531 530 525 + 4 1688 1689 528 524 + 5 1691 1665 492 526 535 + 4 1689 1690 534 528 + 4 1690 1691 535 534 + 5 216 217 523 526 492 + 6 523 524 528 534 535 526 + 5 1707 1519 247 576 575 + 4 1703 1702 565 567 + 4 1702 1707 575 565 + 5 567 565 575 576 570 + 5 1711 1642 462 578 584 + 5 1707 1711 584 587 575 + 5 458 456 586 578 462 + 4 576 575 587 577 + 6 577 587 584 578 586 588 + 4 1713 1702 565 591 + 4 1712 1713 591 589 + 4 276 277 564 573 + 7 573 564 589 591 565 567 566 + 5 1798 1689 528 839 846 + 4 1711 1799 847 584 + 5 1799 1798 846 848 847 + 6 463 462 578 843 845 525 + 5 524 525 845 839 528 + 5 578 584 847 848 843 + 5 839 845 843 848 846 + 5 1663 1801 861 489 490 + 4 1800 1668 498 860 + 4 1801 1800 860 861 + 7 477 478 489 861 860 498 481 + 5 1803 1659 486 857 865 + 6 1664 1805 868 856 519 491 + 4 1805 1803 865 868 + 4 483 491 519 518 + 5 516 518 519 856 858 + 5 858 856 868 865 857 + 5 1804 1801 861 863 866 + 4 1803 1804 866 865 + 4 489 850 863 861 + 6 850 854 857 865 866 863 + 4 1691 1802 864 535 + 5 1802 1805 868 867 864 + 5 491 492 526 527 519 + 4 519 527 853 856 + 6 527 526 535 864 867 853 + 4 856 853 867 868 + 5 1807 1690 534 840 870 + 4 1798 1806 869 846 + 4 1806 1807 870 869 + 4 534 528 839 840 + 5 840 839 846 869 870 + 5 1800 1810 874 862 860 + 5 1810 1809 873 875 874 + 4 495 496 499 497 + 6 496 495 832 875 873 500 + 6 495 497 498 860 862 832 + 4 832 862 874 875 + 5 1713 1814 879 590 591 + 4 1813 1799 847 877 + 4 1814 1813 877 879 + 5 575 565 591 590 587 + 6 584 587 590 879 877 847 + 5 1821 1802 864 896 889 + 5 1807 1821 889 890 870 + 6 535 534 840 891 896 864 + 4 840 870 890 891 + 4 890 889 896 891 + 5 1719 1825 922 924 614 + 5 1825 1814 879 920 922 + 5 612 613 614 924 917 + 6 591 589 612 917 926 590 + 4 879 590 926 920 + 5 917 924 922 920 926 + 4 1824 1825 922 916 + 5 1828 1824 916 937 939 + 4 924 614 940 936 + 5 937 936 940 938 939 + 5 916 922 924 936 937 + 5 1882 1806 869 1091 1095 + 6 1813 1883 1096 1097 878 877 + 4 1883 1882 1095 1096 + 4 848 847 877 878 + 6 846 848 878 1097 1091 869 + 4 1095 1091 1097 1096 + 4 1804 1884 1102 866 + 5 1886 1810 874 1083 1106 + 5 1884 1886 1106 1104 1102 + 5 859 862 860 861 863 + 5 862 859 1085 1083 874 + 6 859 863 866 1102 1104 1085 + 4 1083 1085 1104 1106 + 4 1821 1885 1103 889 + 5 1885 1884 1102 1105 1103 + 4 867 864 896 894 + 7 866 865 868 867 894 1105 1102 + 5 896 889 1103 1105 894 + 4 1882 1887 1107 1095 + 5 1888 1885 1103 1100 1108 + 4 1887 1888 1108 1107 + 5 870 869 1091 1094 890 + 5 889 890 1094 1100 1103 + 6 1094 1091 1095 1107 1108 1100 + 4 1886 1891 1111 1106 + 5 1891 1890 1110 1112 1111 + 4 872 871 873 875 + 6 871 872 1090 1089 1081 876 + 4 1081 1089 1112 1110 + 5 872 875 874 1083 1090 + 6 1090 1083 1106 1111 1112 1089 + 5 1895 1883 1096 1120 1116 + 5 1824 1895 1116 1117 916 + 5 878 877 879 920 927 + 4 878 927 1098 1097 + 7 922 916 1117 1121 1098 927 920 + 5 1096 1097 1098 1121 1120 + 4 1117 1116 1120 1121 + 4 1895 1897 1123 1116 + 4 1889 1887 1107 1109 + 5 1896 1889 1109 1115 1122 + 4 1897 1896 1122 1123 + 6 1095 1096 1120 1115 1109 1107 + 5 1115 1120 1116 1123 1122 + 5 1900 1897 1123 1125 1127 + 5 937 939 1128 1124 1118 + 4 1125 1124 1128 1127 + 4 916 937 1118 1117 + 6 1116 1117 1118 1124 1125 1123 + 4 1888 1934 1243 1108 + 4 1936 1891 1111 1248 + 5 1934 1936 1248 1241 1243 + 4 1099 1104 1102 1105 + 5 1101 1099 1105 1103 1100 + 7 1099 1101 1241 1248 1111 1106 1104 + 5 1101 1100 1108 1243 1241 + 4 1889 1933 1242 1109 + 4 1933 1934 1243 1242 + 5 1108 1107 1109 1242 1243 + 4 1896 1935 1245 1122 + 5 1935 1933 1242 1246 1245 + 4 1109 1115 1246 1242 + 4 1115 1122 1245 1246 + 5 1936 1938 1252 1249 1248 + 5 1938 1937 1251 1250 1252 + 5 1110 1112 1239 1234 1114 + 5 1113 1114 1234 1250 1251 + 5 1112 1111 1248 1249 1239 + 5 1234 1239 1249 1252 1250 + 5 1944 1935 1245 1260 1263 + 5 1947 1944 1263 1270 1268 + 6 1125 1127 1126 1269 1265 1261 + 4 1265 1269 1268 1270 + 6 1122 1123 1125 1261 1260 1245 + 5 1260 1261 1265 1270 1263 + 5 1970 1938 1252 1323 1322 + 5 1944 1970 1322 1333 1263 + 5 1244 1240 1249 1248 1241 + 6 1241 1243 1242 1246 1247 1244 + 5 1246 1245 1260 1262 1247 + 5 1240 1244 1247 1262 1264 + 6 1249 1240 1264 1334 1323 1252 + 6 1262 1260 1263 1333 1334 1264 + 4 1322 1323 1334 1333 + 4 1970 1973 1328 1322 + 4 1973 1972 1327 1328 + 4 1251 1250 1254 1253 + 5 1253 1254 1330 1329 1255 + 5 1250 1252 1323 1330 1254 + 6 1323 1322 1328 1327 1329 1330 + 4 1971 1973 1328 1325 + 4 1267 1266 1270 1268 + 5 1263 1270 1266 1326 1333 + 5 1328 1322 1333 1326 1325 + 4 1340 1339 1344 1342 + 4 1339 1335 1343 1344 + 6 1328 1325 1335 1339 1340 1327 + 6 1583 1587 349 346 341 344 + 4 1587 1584 347 349 + 5 335 328 341 346 338 + 5 1666 1628 438 476 493 + 5 1667 1666 493 495 496 + 6 471 469 497 495 493 476 + 6 1753 1582 343 345 718 724 + 5 1632 1750 720 701 441 + 5 1750 1752 723 721 720 + 4 1752 1753 724 723 + 4 345 697 716 718 + 6 697 702 701 720 721 716 + 5 718 716 721 723 724 + 5 1754 1587 349 714 725 + 4 1753 1754 725 724 + 5 341 345 718 719 346 + 5 714 719 718 724 725 + 5 1751 1589 351 712 722 + 4 1754 1751 722 725 + 5 712 711 714 725 722 + 5 1751 1760 732 730 722 + 4 1760 1764 738 732 + 5 1764 1763 737 739 738 + 4 712 722 730 733 + 6 730 732 738 739 735 733 + 4 1793 1635 445 824 + 5 1666 1794 825 494 493 + 4 1794 1793 824 825 + 6 445 446 465 494 825 824 + 4 465 476 493 494 + 5 1795 1750 720 829 830 + 5 1793 1795 830 828 824 + 6 443 445 824 828 826 709 + 6 701 705 709 826 829 720 + 4 826 828 830 829 + 5 1797 1794 825 836 838 + 5 1808 1797 838 872 871 + 4 825 494 837 836 + 5 494 493 495 832 837 + 6 837 832 875 872 838 836 + 5 1836 1752 723 966 971 + 4 1835 1836 971 967 + 4 1795 1796 831 830 + 4 1796 1823 900 831 + 5 1823 1835 967 981 900 + 5 721 720 829 968 973 + 4 723 721 973 966 + 6 829 830 831 900 981 968 + 6 971 966 973 968 981 967 + 5 1836 1760 732 970 971 + 7 722 725 724 723 966 972 730 + 4 732 730 972 970 + 4 966 971 970 972 + 4 1839 1764 738 985 + 4 1835 1837 982 967 + 4 1837 1838 983 982 + 5 1838 1839 985 984 983 + 5 738 732 970 984 985 + 6 971 967 982 983 984 970 + 5 1845 1780 801 1003 999 + 5 1839 1845 999 1008 985 + 5 739 738 985 1008 1002 + 5 999 1003 1006 1002 1008 + 4 1845 1851 1033 999 + 5 1851 1854 1035 1037 1033 + 5 1003 999 1033 1037 1000 + 5 1877 1796 831 1077 1069 + 4 1797 1822 899 838 + 5 1822 1877 1069 1068 899 + 5 824 825 836 835 828 + 6 830 828 835 1070 1077 831 + 6 835 836 838 899 1068 1070 + 4 1068 1069 1077 1070 + 4 1877 1879 1075 1069 + 5 1878 1823 900 1080 1073 + 4 1879 1878 1073 1075 + 4 900 831 1077 1080 + 5 1069 1075 1073 1080 1077 + 5 1881 1822 899 1088 1082 + 5 1880 1881 1082 1089 1081 + 5 838 872 1090 1088 899 + 4 1082 1088 1090 1089 + 4 1906 1879 1075 1141 + 4 1881 1907 1142 1082 + 5 1907 1906 1141 1140 1142 + 4 1068 899 1088 1086 + 6 1069 1068 1086 1140 1141 1075 + 5 1088 1082 1142 1140 1086 + 5 1878 1911 1151 1150 1073 + 5 1909 1837 982 1145 1147 + 4 1911 1909 1147 1151 + 4 981 900 1080 1074 + 6 967 981 1074 1146 1145 982 + 5 1080 1073 1150 1146 1074 + 5 1145 1146 1150 1151 1147 + 4 1906 1908 1143 1141 + 5 1908 1910 1148 1149 1143 + 4 1910 1911 1151 1148 + 6 1073 1075 1141 1143 1149 1150 + 4 1149 1148 1151 1150 + 4 1916 1838 983 1189 + 4 1909 1917 1191 1147 + 5 1917 1916 1189 1188 1191 + 5 983 982 1145 1188 1189 + 4 1145 1147 1191 1188 + 4 1918 1851 1033 1193 + 5 1916 1919 1194 1192 1189 + 4 1919 1918 1193 1194 + 4 985 984 1007 1008 + 5 984 983 1189 1192 1007 + 7 999 1008 1007 1192 1194 1193 1033 + 5 1920 1876 1067 1208 1196 + 5 1918 1920 1196 1198 1193 + 6 1037 1033 1193 1198 1197 1036 + 5 1032 1036 1197 1208 1067 + 4 1198 1196 1208 1197 + 5 1920 1931 1230 1224 1196 + 4 1931 1930 1229 1230 + 6 1063 1066 1210 1225 1227 1228 + 5 1225 1224 1230 1229 1227 + 5 1066 1064 1067 1208 1210 + 5 1208 1196 1224 1225 1210 + 5 1894 1932 1233 1234 1114 + 5 1932 1907 1142 1235 1233 + 6 1082 1089 1112 1239 1235 1142 + 4 1234 1233 1235 1239 + 4 1942 1932 1233 1256 + 5 1939 1943 1257 1254 1253 + 4 1943 1942 1256 1257 + 6 1233 1234 1250 1254 1257 1256 + 5 1956 1908 1143 1231 1291 + 4 1942 1955 1289 1256 + 4 1955 1956 1291 1289 + 5 1141 1140 1232 1231 1143 + 4 1140 1142 1235 1232 + 7 1231 1232 1235 1233 1256 1289 1291 + 4 1957 1910 1148 1292 + 5 1956 1959 1294 1287 1291 + 4 1959 1957 1292 1294 + 4 1149 1143 1231 1237 + 6 1148 1149 1237 1287 1294 1292 + 4 1237 1231 1291 1287 + 4 1958 1917 1191 1293 + 4 1957 1958 1293 1292 + 6 1147 1151 1148 1292 1293 1191 + 5 1960 1919 1194 1202 1309 + 5 1958 1962 1312 1297 1293 + 5 1962 1960 1309 1310 1312 + 4 1189 1188 1190 1192 + 5 1192 1190 1203 1202 1194 + 7 1190 1188 1191 1293 1297 1295 1203 + 5 1202 1203 1295 1310 1309 + 4 1295 1297 1312 1310 + 4 1961 1931 1230 1311 + 5 1960 1961 1311 1308 1309 + 4 1230 1224 1308 1311 + 4 1193 1194 1202 1198 + 6 1196 1198 1202 1309 1308 1224 + 4 1961 1968 1320 1311 + 5 1229 1230 1311 1320 1319 + 5 1976 1943 1257 1331 1341 + 4 1975 1976 1341 1338 + 4 1257 1254 1330 1331 + 5 1330 1329 1338 1341 1331 + 5 1981 1955 1289 1288 1345 + 4 1976 1982 1347 1341 + 5 1982 1981 1345 1346 1347 + 6 1256 1257 1331 1332 1288 1289 + 4 1288 1332 1346 1345 + 5 1332 1331 1341 1347 1346 + 5 1990 1959 1294 1304 1363 + 4 1981 1988 1359 1345 + 5 1988 1990 1363 1364 1359 + 5 1287 1290 1303 1304 1294 + 5 1290 1287 1291 1289 1288 + 6 1290 1288 1345 1359 1364 1303 + 4 1304 1303 1364 1363 + 4 1989 1962 1312 1362 + 4 1990 1989 1362 1363 + 5 1293 1292 1294 1304 1297 + 5 1297 1304 1363 1362 1312 + 4 1989 1995 1370 1362 + 5 1311 1308 1316 1321 1320 + 5 1316 1315 1368 1365 1321 + 5 1308 1309 1310 1315 1316 + 6 1310 1312 1362 1370 1368 1315 + 4 1998 1982 1347 1374 + 4 1339 1344 1372 1373 + 7 1338 1340 1339 1373 1374 1347 1341 + 5 2004 1988 1359 1360 1378 + 5 1356 1350 1371 1376 1379 + 4 1360 1356 1379 1378 + 6 1345 1346 1350 1356 1360 1359 + 5 1346 1347 1374 1371 1350 + 5 1361 1360 1378 1377 1369 + 4 1359 1360 1361 1364 + 6 1364 1361 1369 1370 1362 1363 + 5 1680 1715 610 574 508 + 4 1715 1716 611 610 + 5 564 573 574 610 611 + 4 1556 1563 311 306 + 5 1723 1560 309 624 621 + 5 1563 1723 621 620 311 + 5 298 306 311 620 630 + 5 620 621 624 626 630 + 4 1728 1725 631 640 + 5 1725 1563 311 646 631 + 6 302 303 644 646 311 306 + 5 640 631 646 644 635 + 4 1729 1725 631 643 + 5 1625 1729 643 634 436 + 5 631 640 642 634 643 + 4 1723 1721 616 621 + 5 1730 1673 502 648 649 + 5 1721 1730 649 650 616 + 5 621 616 650 654 624 + 4 649 648 654 650 + 4 1729 1738 678 643 + 4 1737 1721 616 677 + 5 1738 1737 677 676 678 + 4 620 311 646 641 + 6 616 621 620 641 676 677 + 6 631 643 678 676 641 646 + 5 1785 1738 678 747 805 + 5 1757 1786 806 751 727 + 4 1786 1785 805 806 + 5 643 634 744 747 678 + 6 744 740 751 806 805 747 + 4 1730 1816 881 649 + 5 1817 1678 506 652 882 + 4 1816 1817 882 881 + 6 647 648 649 881 882 652 + 5 1737 1739 679 675 677 + 4 1739 1815 880 679 + 4 1815 1816 881 880 + 4 650 616 677 675 + 6 649 650 675 679 880 881 + 5 1820 1679 507 659 887 + 5 1817 1818 885 883 882 + 4 1818 1820 887 885 + 4 674 652 882 883 + 7 659 665 672 674 883 885 887 + 4 1819 1715 610 886 + 5 1820 1819 886 884 887 + 6 574 569 663 884 886 610 + 4 663 659 887 884 + 5 1819 1830 941 921 886 + 5 1830 1829 940 936 941 + 6 611 610 886 921 917 612 + 5 917 921 941 936 924 + 5 1834 1739 679 947 965 + 5 1785 1833 964 946 805 + 4 1833 1834 965 964 + 5 675 677 676 951 942 + 5 676 678 747 950 951 + 4 679 675 942 947 + 4 747 805 946 950 + 7 947 942 951 950 946 964 965 + 5 1831 1815 880 958 961 + 5 1832 1831 961 962 963 + 4 1834 1832 963 965 + 5 880 679 947 959 958 + 5 959 947 965 963 962 + 4 958 959 962 961 + 5 1844 1786 806 998 995 + 5 1789 1844 995 993 808 + 5 751 748 986 998 806 + 5 986 991 993 995 998 + 4 1844 1867 1055 995 + 4 1868 1833 964 1057 + 5 1867 1868 1057 1056 1055 + 5 805 806 998 997 946 + 5 964 946 997 1056 1057 + 5 998 995 1055 1056 997 + 5 1858 1870 1059 1041 1042 + 4 1869 1867 1055 1058 + 4 1870 1869 1058 1059 + 6 995 993 1041 1059 1058 1055 + 5 1903 1818 885 955 1130 + 4 1831 1904 1131 961 + 4 1904 1903 1130 1131 + 6 881 880 958 957 883 882 + 4 885 883 957 955 + 6 955 957 958 961 1131 1130 + 4 1902 1830 941 1129 + 5 1903 1902 1129 1132 1130 + 4 886 884 928 921 + 6 884 887 885 955 956 928 + 6 921 928 956 1132 1129 941 + 4 956 955 1130 1132 + 6 1912 1901 1128 1124 1174 1173 + 5 1902 1912 1173 1170 1129 + 7 937 936 941 1129 1170 1171 1118 + 4 1124 1118 1171 1174 + 4 1171 1170 1173 1174 + 5 1832 1913 1177 1180 963 + 4 1913 1914 1178 1177 + 4 1905 1904 1131 1133 + 5 1914 1905 1133 1184 1178 + 4 962 963 1180 1179 + 6 961 962 1179 1184 1133 1131 + 5 1177 1178 1184 1179 1180 + 5 1868 1915 1183 1181 1057 + 4 1915 1913 1177 1183 + 6 963 965 964 1057 1181 1180 + 4 1177 1180 1181 1183 + 5 1921 1870 1059 1212 1201 + 5 1871 1921 1201 1218 1061 + 5 1041 1040 1204 1212 1059 + 4 1043 1061 1218 1219 + 5 1201 1212 1204 1219 1218 + 5 1869 1923 1220 1211 1058 + 4 1924 1915 1183 1222 + 5 1923 1924 1222 1221 1220 + 4 1057 1056 1186 1181 + 6 1056 1055 1058 1211 1215 1186 + 6 1183 1181 1186 1215 1221 1222 + 4 1215 1211 1220 1221 + 4 1921 1926 1226 1201 + 4 1925 1923 1220 1223 + 4 1926 1925 1223 1226 + 4 1058 1059 1212 1211 + 6 1212 1201 1226 1223 1220 1211 + 5 1927 1926 1226 1225 1227 + 5 1061 1060 1066 1210 1218 + 5 1201 1218 1210 1225 1226 + 4 1950 1914 1178 1274 + 4 1924 1949 1273 1222 + 4 1949 1950 1274 1273 + 6 1178 1177 1183 1222 1273 1274 + 4 1912 1951 1275 1173 + 5 1953 1948 1269 1265 1278 + 5 1951 1953 1278 1276 1275 + 5 1125 1124 1174 1258 1261 + 5 1174 1173 1275 1276 1258 + 5 1261 1258 1276 1278 1265 + 5 1905 1954 1279 1166 1133 + 4 1954 1951 1275 1279 + 4 1129 1132 1169 1170 + 6 1130 1131 1133 1166 1169 1132 + 6 1169 1166 1279 1275 1173 1170 + 6 1950 1952 1277 1272 1271 1274 + 4 1952 1954 1279 1277 + 5 1166 1133 1184 1182 1167 + 4 1167 1182 1271 1272 + 5 1166 1167 1272 1277 1279 + 5 1184 1178 1274 1271 1182 + 4 1925 1963 1313 1223 + 5 1965 1949 1273 1298 1318 + 5 1963 1964 1317 1314 1313 + 4 1964 1965 1318 1317 + 5 1222 1221 1307 1298 1273 + 6 1221 1220 1223 1313 1314 1307 + 5 1298 1307 1314 1317 1318 + 5 1969 1963 1313 1316 1321 + 7 1223 1226 1225 1224 1308 1316 1313 + 4 1953 1983 1352 1278 + 4 1984 1974 1336 1353 + 4 1983 1984 1353 1352 + 7 1270 1265 1278 1352 1353 1336 1266 + 5 1985 1952 1277 1285 1355 + 4 1965 1987 1358 1318 + 5 1987 1985 1355 1354 1358 + 4 1272 1271 1299 1300 + 5 1277 1272 1300 1301 1285 + 5 1271 1274 1273 1298 1299 + 4 1285 1301 1354 1355 + 7 1299 1298 1318 1358 1354 1301 1300 + 5 1986 1983 1352 1349 1357 + 4 1985 1986 1357 1355 + 6 1276 1275 1279 1277 1285 1280 + 5 1278 1276 1280 1349 1352 + 5 1280 1285 1355 1357 1349 + 4 1993 1964 1317 1366 + 4 1314 1313 1316 1315 + 5 1314 1315 1368 1366 1317 + 4 1994 1987 1358 1367 + 5 1318 1317 1366 1367 1358 + 5 1984 1999 1375 1348 1353 + 4 1337 1336 1353 1348 + 6 1335 1337 1348 1375 1373 1339 + 5 1986 2005 1379 1356 1357 + 5 1351 1348 1353 1352 1349 + 5 1351 1349 1357 1356 1350 + 5 1348 1351 1350 1371 1375 + 6 1355 1354 1361 1360 1356 1357 + 5 1354 1358 1367 1369 1361 + 6 112 110 113 205 202 196 + 6 195 196 202 212 208 197 + 5 202 205 203 215 212 + 6 196 193 220 270 271 202 + 5 205 202 271 273 234 + 5 220 219 227 272 270 + 6 227 232 238 234 273 272 + 4 271 270 272 273 + 6 148 155 157 375 358 170 + 5 374 358 375 376 359 + 6 160 158 231 379 377 362 + 6 235 230 319 378 379 231 + 6 319 315 320 360 381 378 + 4 360 362 377 381 + 4 377 379 378 381 + 7 163 166 254 380 420 418 172 + 6 242 231 379 382 257 239 + 5 254 252 257 382 380 + 7 375 358 412 414 377 362 365 + 6 379 377 414 420 380 382 + 4 414 412 418 420 + 4 254 380 401 400 + 4 286 403 409 408 + 4 401 380 420 419 + 7 394 400 401 419 421 409 403 + 5 407 408 409 421 413 + 7 410 413 421 419 420 418 415 + 5 202 212 531 532 271 + 5 223 220 270 517 522 + 5 270 271 532 529 517 + 7 522 517 529 527 519 518 520 + 6 523 526 527 529 532 531 + 4 234 263 274 273 + 5 263 260 450 453 274 + 6 271 273 274 453 533 532 + 6 453 450 461 451 530 533 + 4 530 531 532 533 + 5 244 227 272 314 313 + 6 272 270 517 545 546 314 + 6 313 314 546 544 316 318 + 5 517 522 521 539 545 + 5 539 538 544 546 545 + 6 257 256 258 550 551 382 + 6 258 262 263 274 547 550 + 6 273 272 314 553 547 274 + 6 314 313 319 378 552 553 + 5 378 379 382 551 552 + 5 550 547 553 552 551 + 6 259 258 550 603 597 267 + 5 382 380 401 548 551 + 6 400 399 560 555 548 401 + 6 551 548 555 601 603 550 + 5 555 560 563 594 601 + 4 594 597 603 601 + 5 453 274 547 599 598 + 5 450 453 598 602 454 + 4 547 550 603 599 + 6 597 596 602 598 599 603 + 4 546 314 553 549 + 5 453 533 604 606 598 + 5 529 517 545 608 605 + 5 532 529 605 604 533 + 5 545 546 549 609 608 + 6 553 547 599 607 609 549 + 4 599 598 606 607 + 6 604 605 608 609 607 606 + 6 297 291 618 636 645 354 + 6 402 395 403 409 627 619 + 7 404 405 637 632 627 409 408 + 6 618 629 619 627 632 636 + 4 636 632 637 645 + 6 622 618 636 641 620 630 + 6 633 644 646 641 636 645 + 5 372 360 381 685 688 + 5 381 378 552 694 685 + 6 544 542 682 683 549 546 + 5 553 549 683 694 552 + 6 683 682 690 688 685 694 + 6 384 387 699 717 710 392 + 5 695 697 716 717 699 + 6 713 710 717 716 718 719 + 6 377 381 685 755 760 414 + 7 388 389 390 422 759 757 689 + 6 412 414 760 756 424 416 + 6 685 688 686 689 757 755 + 5 755 757 759 756 760 + 5 419 401 548 758 754 + 5 414 420 419 754 760 + 6 548 551 552 694 752 758 + 4 694 685 755 752 + 5 752 755 760 754 758 + 6 689 693 698 771 769 757 + 5 698 699 717 772 771 + 4 717 710 775 772 + 5 753 759 757 769 770 + 6 768 770 769 771 772 775 + 6 421 409 627 763 778 786 + 5 419 421 786 779 754 + 5 555 548 758 767 766 + 6 554 560 555 766 762 623 + 5 619 623 762 763 627 + 5 758 754 779 782 767 + 6 763 762 766 767 782 778 + 4 778 782 779 786 + 5 421 413 429 784 786 + 4 632 627 763 765 + 5 637 632 765 761 746 + 5 743 746 761 777 781 + 5 761 765 763 778 777 + 6 777 778 786 784 785 781 + 5 754 760 756 783 779 + 5 779 783 780 784 786 + 6 467 465 494 837 833 814 + 5 709 696 816 827 826 + 6 818 814 833 834 827 816 + 5 826 827 834 835 828 + 5 834 833 837 836 835 + 6 525 530 533 604 841 845 + 7 586 578 843 842 593 583 585 + 7 595 593 842 844 606 598 602 + 4 604 606 844 841 + 5 841 844 842 843 845 + 4 811 513 851 849 + 6 810 811 849 852 833 814 + 6 832 837 833 852 859 862 + 6 849 851 850 863 859 852 + 6 529 527 853 897 895 605 + 6 541 539 545 608 821 822 + 5 608 605 895 892 821 + 6 811 822 821 892 888 849 + 8 851 849 888 897 853 856 858 855 + 4 888 892 895 897 + 5 605 604 841 893 895 + 6 839 840 891 893 841 845 + 4 867 853 897 894 + 6 893 891 896 894 897 895 + 5 549 609 908 907 683 + 5 609 608 821 903 908 + 6 681 682 683 907 904 819 + 7 822 812 823 819 904 903 821 + 4 903 904 907 908 + 5 555 601 913 915 766 + 7 603 599 607 905 912 913 601 + 4 607 609 908 905 + 5 683 694 752 902 907 + 5 752 758 767 906 902 + 5 767 766 915 914 906 + 7 902 906 914 912 905 908 907 + 4 913 912 914 915 + 6 600 594 601 913 911 664 + 5 623 628 653 764 762 + 6 653 656 669 909 910 764 + 5 670 664 911 909 669 + 5 762 764 910 915 766 + 5 910 909 911 913 915 + 7 577 581 666 919 926 590 587 + 6 668 663 884 928 919 666 + 5 921 917 926 919 928 + 5 593 661 925 923 842 + 5 661 662 666 919 925 + 6 843 842 923 927 878 848 + 6 925 919 926 920 927 923 + 6 606 607 905 934 935 844 + 5 664 661 925 918 911 + 5 842 844 935 932 923 + 4 905 912 931 934 + 6 913 911 918 930 931 912 + 5 918 925 923 932 930 + 5 931 930 932 935 934 + 4 892 821 903 901 + 5 844 841 893 929 935 + 6 895 892 901 933 929 893 + 6 901 903 908 905 934 933 + 4 929 933 934 935 + 7 632 636 641 676 951 948 765 + 8 650 654 655 653 764 943 942 675 + 6 762 763 765 948 943 764 + 4 942 943 948 951 + 7 744 747 950 944 761 746 749 + 4 765 761 944 948 + 4 948 944 950 951 + 7 673 669 909 953 957 883 674 + 4 910 764 943 949 + 5 909 910 949 952 953 + 6 943 942 947 959 952 949 + 5 953 952 959 958 957 + 5 911 909 953 954 918 + 6 925 918 954 956 928 919 + 5 954 953 957 955 956 + 7 703 698 771 975 969 820 700 + 7 755 752 902 978 979 769 757 + 4 771 769 979 975 + 6 819 817 820 969 974 904 + 5 902 907 904 974 978 + 5 974 969 975 979 978 + 6 716 717 772 976 973 721 + 4 772 771 975 976 + 5 820 816 827 977 969 + 5 827 826 829 968 977 + 6 968 973 976 975 969 977 + 6 733 729 774 980 972 730 + 5 775 772 976 980 774 + 5 966 972 980 976 973 + 6 776 774 980 1004 1009 800 + 6 972 970 984 1007 1004 980 + 6 1002 1005 1009 1004 1007 1008 + 6 761 777 1021 1023 990 944 + 5 777 781 795 1012 1021 + 5 950 944 990 997 946 + 8 996 986 998 997 990 1023 1022 988 + 4 1021 1012 1022 1023 + 5 782 767 906 1020 1024 + 6 769 770 789 1027 1016 979 + 6 779 782 1024 1028 791 783 + 5 906 902 978 1015 1020 + 4 978 979 1016 1015 + 6 1015 1016 1027 1028 1024 1020 + 5 778 777 1021 1024 782 + 5 914 906 1020 1026 945 + 5 910 915 914 945 949 + 8 948 943 949 945 1026 1025 990 944 + 3 1023 990 1025 + 6 1020 1024 1021 1023 1025 1026 + 7 975 976 980 1004 1011 1016 979 + 4 1004 1009 1019 1011 + 6 1016 1011 1019 1017 1018 1027 + 5 1010 1012 1021 1024 1028 + 5 834 827 977 1079 1072 + 6 833 834 1072 1076 898 852 + 4 849 852 898 888 + 6 892 888 898 1076 1071 901 + 6 903 901 1071 1078 974 904 + 5 969 974 1078 1079 977 + 5 1071 1076 1072 1079 1078 + 4 834 835 1070 1072 + 5 968 977 1079 1074 981 + 6 1072 1070 1077 1080 1074 1079 + 5 852 859 1085 1087 898 + 4 1076 898 1087 1084 + 6 1068 1070 1072 1076 1084 1086 + 7 1085 1083 1090 1088 1086 1084 1087 + 6 890 891 893 929 1093 1094 + 5 923 927 1098 1092 932 + 5 929 935 932 1092 1093 + 6 1091 1094 1093 1092 1098 1097 + 7 888 897 894 1105 1099 1087 898 + 4 1085 1087 1099 1104 + 5 901 933 1137 1134 1071 + 5 933 929 1093 1139 1137 + 5 1076 1071 1134 1135 1084 + 6 1087 1084 1135 1136 1101 1099 + 6 1093 1094 1100 1101 1136 1139 + 5 1135 1134 1137 1139 1136 + 6 914 912 931 1157 1154 945 + 6 931 934 933 1137 1160 1157 + 4 1026 945 1154 1163 + 6 974 978 1015 1152 1159 1078 + 5 1015 1020 1026 1163 1152 + 5 1071 1078 1159 1155 1134 + 4 1137 1134 1155 1160 + 7 1159 1152 1163 1154 1157 1160 1155 + 4 918 930 960 954 + 5 930 931 1157 1164 960 + 5 945 949 952 1153 1154 + 6 952 953 954 960 1164 1153 + 4 1154 1153 1164 1157 + 7 932 930 960 1175 1172 1119 1092 + 6 954 956 1132 1169 1175 960 + 4 1098 1092 1119 1121 + 6 1118 1117 1121 1119 1172 1171 + 5 1169 1170 1171 1172 1175 + 4 1164 960 1175 1176 + 5 1092 1093 1139 1138 1119 + 4 1119 1138 1165 1172 + 6 1139 1137 1160 1168 1165 1138 + 5 1160 1157 1164 1176 1168 + 5 1165 1168 1176 1175 1172 + 6 959 952 1153 1185 1179 962 + 7 990 997 1056 1186 1187 1156 1025 + 4 1026 1025 1156 1163 + 6 1153 1154 1163 1156 1187 1185 + 6 1180 1179 1185 1187 1186 1181 + 6 1164 1153 1185 1182 1167 1176 + 5 1167 1166 1169 1175 1176 + 4 1179 1184 1182 1185 + 6 1007 1004 1011 1144 1190 1192 + 6 1011 1016 1015 1152 1161 1144 + 6 1079 1074 1146 1162 1159 1078 + 7 1144 1161 1162 1146 1145 1188 1190 + 4 1152 1159 1162 1161 + 8 1022 1014 1046 1213 1216 1156 1025 1023 + 4 1187 1156 1216 1217 + 4 1186 1187 1217 1215 + 8 1206 1204 1212 1211 1215 1217 1216 1213 + 6 1019 1011 1144 1207 1200 1045 + 4 1036 1051 1195 1197 + 4 1144 1190 1203 1207 + 8 1197 1195 1214 1200 1207 1203 1202 1198 + 4 1161 1144 1207 1199 + 6 1152 1161 1199 1216 1156 1163 + 5 1199 1207 1200 1213 1216 + 7 1195 1197 1208 1210 1218 1219 1209 + 6 1084 1086 1140 1232 1236 1135 + 6 1134 1135 1236 1238 1158 1155 + 7 1150 1146 1162 1158 1238 1237 1149 + 4 1155 1158 1162 1159 + 5 1232 1231 1237 1238 1236 + 4 1136 1101 1241 1244 + 5 1135 1136 1244 1240 1236 + 6 1235 1232 1236 1240 1249 1239 + 7 1120 1115 1246 1247 1138 1119 1121 + 5 1136 1139 1138 1247 1244 + 5 1138 1165 1259 1262 1247 + 6 1165 1172 1171 1174 1258 1259 + 5 1259 1258 1261 1260 1262 + 4 1238 1158 1282 1284 + 6 1158 1155 1160 1168 1283 1282 + 5 1168 1165 1259 1281 1283 + 6 1236 1238 1284 1286 1264 1240 + 5 1259 1262 1264 1286 1281 + 5 1283 1281 1286 1284 1282 + 7 1162 1158 1282 1296 1305 1199 1161 + 5 1207 1199 1305 1295 1203 + 5 1238 1237 1287 1290 1284 + 5 1282 1284 1290 1303 1296 + 6 1297 1295 1305 1296 1303 1304 + 7 1167 1176 1168 1283 1302 1300 1272 + 7 1185 1182 1271 1299 1306 1217 1187 + 5 1199 1216 1217 1306 1305 + 4 1283 1282 1296 1302 + 6 1302 1296 1305 1306 1299 1300 + 5 1258 1259 1281 1280 1276 + 6 1280 1281 1283 1302 1301 1285 + 3 1300 1301 1302 + 5 1217 1215 1221 1307 1306 + 4 1298 1299 1306 1307 + 7 1305 1295 1310 1315 1314 1307 1306 + 4 1286 1264 1334 1324 + 6 1284 1286 1324 1332 1288 1290 + 6 1323 1330 1331 1332 1324 1334 + 6 1281 1280 1349 1351 1324 1286 + 7 1334 1324 1351 1348 1337 1326 1333 + 7 1296 1302 1301 1354 1361 1364 1303 + 5 1324 1332 1346 1350 1351 + 4 4 2092 1380 2016 + 4 4 2093 1405 2092 + 4 4 2023 1385 2093 + 4 4 2095 1384 2023 + 4 4 2094 1407 2095 + 4 4 2016 1383 2094 + 4 3 2016 1380 2089 + 4 3 2090 1383 2016 + 4 3 2021 1381 2090 + 4 3 2091 1382 2021 + 4 3 2019 1402 2091 + 4 3 2089 1403 2019 + 8 1380 2092 1405 1406 1404 2146 1403 2089 + 4 43 2254 1381 2021 + 4 43 2255 1409 2254 + 4 43 2075 1411 2255 + 4 43 2257 1410 2075 + 4 43 2256 1412 2257 + 4 43 2021 1382 2256 + 9 1381 2254 1409 1424 1423 1407 2094 1383 2090 + 9 1382 2091 1402 2148 1408 1413 1414 1412 2256 + 7 1384 2095 1407 1423 1427 1417 2106 + 4 7 2023 1384 2106 + 4 7 2104 1385 2023 + 4 7 2105 1416 2104 + 4 7 2031 1419 2105 + 4 7 2107 1420 2031 + 4 7 2106 1417 2107 + 8 1385 2104 1416 1425 1426 1406 1405 2093 + 7 1386 2102 1415 1460 1458 1389 2084 + 4 6 2102 1386 2008 + 4 6 2103 1415 2102 + 4 6 2030 1421 2103 + 4 6 2101 1422 2030 + 4 6 2100 1418 2101 + 4 6 2008 1387 2100 + 4 1 2008 1386 2084 + 4 1 2083 1387 2008 + 4 1 2082 1388 2083 + 4 1 2007 1391 2082 + 4 1 2085 1390 2007 + 4 1 2084 1389 2085 + 8 1387 2083 1388 1443 1463 1445 1418 2100 + 9 1388 2082 1391 2086 1392 2111 1438 1444 1443 + 9 1389 1458 1461 1399 2251 1395 2087 1390 2085 + 4 2 2007 1390 2087 + 4 2 2086 1391 2007 + 4 2 2010 1392 2086 + 4 2 2088 1393 2010 + 4 2 2013 1394 2088 + 4 2 2087 1395 2013 + 4 9 2111 1392 2010 + 4 9 2112 1438 2111 + 4 9 2040 1396 2112 + 4 9 2114 1397 2040 + 4 9 2113 1439 2114 + 4 9 2010 1393 2113 + 9 1393 2088 1394 2252 1398 1466 1468 1439 2113 + 4 42 2252 1394 2013 + 4 42 2253 1398 2252 + 4 42 2073 1400 2253 + 4 42 2250 1401 2073 + 4 42 2251 1399 2250 + 4 42 2013 1395 2251 + 4 11 2119 1396 2040 + 4 11 2120 1441 2119 + 4 11 2121 1450 2120 + 4 11 2050 1448 2121 + 4 11 2124 1449 2050 + 4 11 2123 1451 2124 + 4 11 2122 1440 2123 + 4 11 2040 1397 2122 + 7 1396 2119 1441 1442 1444 1438 2112 + 7 1397 2114 1439 1468 1467 1440 2122 + 7 1398 2253 1400 2268 1471 1470 1466 + 8 1399 1461 1462 1464 1465 2266 1401 2250 + 4 46 2268 1400 2073 + 4 46 2270 1471 2268 + 4 46 2269 1469 2270 + 4 46 2012 1456 2269 + 4 46 2267 1457 2012 + 4 46 2266 1465 2267 + 4 46 2073 1401 2266 + 4 17 2148 1402 2019 + 4 17 2149 1408 2148 + 4 17 2060 1483 2149 + 4 17 2147 1482 2060 + 4 17 2146 1404 2147 + 4 17 2019 1403 2146 + 8 1404 1406 1426 1495 1491 2221 1482 2147 + 7 1408 2149 1483 2223 1492 1493 1413 + 8 1409 2255 1411 2271 1499 1496 1497 1424 + 7 1410 2257 1412 1414 1501 1500 2273 + 4 47 2075 1410 2273 + 4 47 2271 1411 2075 + 4 47 2272 1499 2271 + 4 47 2035 1480 2272 + 4 47 2274 1479 2035 + 4 47 2275 1498 2274 + 4 47 2273 1500 2275 + 6 1413 1493 1502 1503 1501 1414 + 8 1415 2103 1421 2168 1511 1512 1513 1460 + 8 1416 2105 1419 2166 1514 1510 1504 1425 + 8 1417 1427 1515 1512 1511 2169 1420 2107 + 8 1418 1445 1447 1510 1514 2167 1422 2101 + 4 22 2166 1419 2031 + 4 22 2167 1514 2166 + 4 22 2030 1422 2167 + 4 22 2168 1421 2030 + 4 22 2169 1511 2168 + 4 22 2031 1420 2169 + 7 1423 1424 1497 1528 1529 1515 1427 + 7 1425 1504 1505 1506 1494 1495 1426 + 8 1428 2172 1574 1576 1575 2078 1433 2109 + 4 23 2172 1428 2037 + 4 23 2173 1574 2172 + 4 23 2057 1452 2173 + 4 23 2170 1453 2057 + 4 23 2171 1573 2170 + 4 23 2037 1429 2171 + 4 8 2037 1428 2109 + 4 8 2108 1429 2037 + 4 8 2038 1430 2108 + 4 8 2110 1431 2038 + 4 8 2039 1432 2110 + 4 8 2109 1433 2039 + 8 1429 2108 1430 2189 1569 1571 1573 2171 + 4 27 2189 1430 2038 + 4 27 2190 1569 2189 + 4 27 2033 1580 2190 + 4 27 2192 1581 2033 + 4 27 2191 1583 2192 + 4 27 2038 1431 2191 + 8 1431 2110 1432 2080 1584 1587 1583 2191 + 4 0 2080 1432 2039 + 4 0 2081 1584 2080 + 4 0 2049 1585 2081 + 4 0 2079 1586 2049 + 4 0 2078 1575 2079 + 4 0 2039 1433 2078 + 7 1434 2308 1553 1590 1591 1543 2304 + 4 55 2308 1434 2072 + 4 55 2309 1553 2308 + 4 55 2006 1552 2309 + 4 55 2307 1551 2006 + 4 55 2306 1549 2307 + 4 55 2072 1435 2306 + 4 54 2072 1434 2304 + 4 54 2303 1435 2072 + 4 54 2302 1544 2303 + 4 54 2014 1437 2302 + 4 54 2305 1436 2014 + 4 54 2304 1543 2305 + 8 1435 2303 1544 1542 1545 1548 1549 2306 + 8 1436 2305 1543 1591 1592 1540 1454 2260 + 4 44 2014 1436 2260 + 4 44 2258 1437 2014 + 4 44 2259 1455 2258 + 4 44 2012 1457 2259 + 4 44 2261 1456 2012 + 4 44 2260 1454 2261 + 7 1437 2258 1455 1546 1542 1544 2302 + 7 1440 1467 1595 1596 1599 1451 2123 + 7 1441 2120 1450 1601 1598 1602 1442 + 5 1442 1602 1463 1443 1444 + 7 1445 1463 1602 1598 1566 1446 1447 + 6 1446 1564 1505 1504 1510 1447 + 6 1446 1566 1568 1567 1565 1564 + 4 13 2129 1448 2050 + 4 13 2130 1473 2129 + 4 13 2055 1476 2130 + 4 13 2132 1477 2055 + 4 13 2131 1474 2132 + 4 13 2050 1449 2131 + 8 1448 2129 1473 1603 1597 1601 1450 2121 + 7 1449 2124 1451 1599 1600 1474 2131 + 8 1452 2135 1472 1606 1605 1576 1574 2173 + 4 14 2135 1452 2057 + 4 14 2136 1472 2135 + 4 14 2055 1477 2136 + 4 14 2134 1476 2055 + 4 14 2133 1475 2134 + 4 14 2057 1453 2133 + 8 1453 2170 1573 1571 1570 1572 1475 2133 + 8 1454 1540 1610 1478 1469 2269 1456 2261 + 8 1455 2259 1457 2267 1465 1464 1608 1546 + 7 1458 1460 1513 1509 1459 1462 1461 + 6 1459 1509 1527 1531 1530 1526 + 6 1459 1526 1609 1608 1464 1462 + 6 1466 1470 1612 1595 1467 1468 + 7 1469 1478 1611 1612 1470 1471 2270 + 9 1472 2136 1477 2132 1474 1600 1615 1614 1606 + 8 1473 2130 1476 2134 1475 1572 1604 1603 + 5 1478 1610 1619 1617 1611 + 7 1479 2274 1498 1643 1642 1516 2283 + 4 49 2035 1479 2283 + 4 49 2280 1480 2035 + 4 49 2281 1481 2280 + 4 49 2282 1522 2281 + 4 49 2046 1520 2282 + 4 49 2284 1521 2046 + 4 49 2283 1516 2284 + 7 1480 2280 1481 1638 1496 1499 2272 + 6 1481 2281 1522 1640 1639 1638 + 4 35 2060 1482 2221 + 4 35 2223 1483 2060 + 4 35 2224 1492 2223 + 4 35 2225 1658 2224 + 4 35 2077 1656 2225 + 4 35 2222 1655 2077 + 4 35 2221 1491 2222 + 9 1484 2198 1485 2154 1488 2213 1648 1650 1647 + 4 29 2198 1484 2197 + 4 29 2062 1485 2198 + 4 29 2199 1486 2062 + 4 29 2200 1628 2199 + 4 29 2054 1627 2200 + 4 29 2197 1626 2054 + 8 1484 1647 1644 1634 1636 2209 1626 2197 + 4 19 2154 1485 2062 + 4 19 2065 1488 2154 + 4 19 2155 1487 2065 + 4 19 2067 1490 2155 + 4 19 2156 1489 2067 + 4 19 2062 1486 2156 + 8 1486 2199 1628 1666 1667 2244 1489 2156 + 8 1487 2155 1490 2242 1669 1668 1654 2215 + 4 33 2065 1487 2215 + 4 33 2213 1488 2065 + 4 33 2214 1648 2213 + 4 33 2074 1652 2214 + 4 33 2216 1651 2074 + 4 33 2215 1654 2216 + 4 40 2067 1489 2244 + 4 40 2242 1490 2067 + 4 40 2243 1669 2242 + 4 40 2076 1671 2243 + 4 40 2245 1670 2076 + 4 40 2244 1667 2245 + 8 1491 1495 1494 1685 1657 2226 1655 2222 + 7 1492 2224 1658 1664 1665 1502 1493 + 6 1494 1506 1507 1687 1686 1685 + 7 1496 1638 1639 1637 1533 1528 1497 + 7 1498 2275 1500 1501 1503 1688 1643 + 7 1502 1665 1691 1690 1689 1688 1503 + 6 1505 1564 1565 1508 1507 1506 + 6 1507 1508 1695 1694 1693 1687 + 5 1508 1565 1567 1692 1695 + 6 1509 1513 1512 1515 1529 1527 + 8 1516 1642 1711 1707 1519 2288 1521 2284 + 4 67 2355 1517 2052 + 4 67 2354 1704 2355 + 4 67 2066 1525 2354 + 4 67 2357 1524 2066 + 4 67 2356 1703 2357 + 4 67 2052 1518 2356 + 4 50 2052 1517 2285 + 4 50 2287 1518 2052 + 4 50 2288 1519 2287 + 4 50 2046 1521 2288 + 4 50 2286 1520 2046 + 4 50 2285 1523 2286 + 8 1517 2355 1704 1705 1706 1708 1523 2285 + 7 1518 2287 1519 1707 1702 1703 2356 + 8 1520 2286 1523 1708 1709 1640 1522 2282 + 9 1524 2357 1703 1702 1713 1712 2246 1537 2295 + 4 52 2066 1524 2295 + 4 52 2294 1525 2066 + 4 52 2064 1534 2294 + 4 52 2296 1535 2064 + 4 52 2068 1536 2296 + 4 52 2295 1537 2068 + 8 1525 2294 1534 2346 1681 1705 1704 2354 + 7 1526 1530 1701 1696 1697 1607 1609 + 6 1527 1529 1528 1533 1532 1531 + 6 1530 1531 1532 1714 1700 1701 + 5 1532 1533 1637 1641 1714 + 4 65 2346 1534 2064 + 4 65 2347 1681 2346 + 4 65 2045 1682 2347 + 4 65 2349 1683 2045 + 4 65 2348 1680 2349 + 4 65 2064 1535 2348 + 8 1535 2296 1536 2248 1716 1715 1680 2348 + 4 41 2248 1536 2068 + 4 41 2249 1716 2248 + 4 41 2027 1717 2249 + 4 41 2247 1718 2027 + 4 41 2246 1712 2247 + 4 41 2068 1537 2246 + 4 57 2315 1538 2017 + 4 57 2314 1550 2315 + 4 57 2015 1555 2314 + 4 57 2317 1554 2015 + 4 57 2316 1556 2317 + 4 57 2017 1539 2316 + 4 60 2017 1538 2325 + 4 60 2327 1539 2017 + 4 60 2328 1560 2327 + 4 60 2025 1562 2328 + 4 60 2326 1561 2025 + 4 60 2325 1559 2326 + 7 1538 2315 1550 1547 1724 1559 2325 + 7 1539 2327 1560 1723 1563 1556 2316 + 6 1540 1592 1620 1621 1619 1610 + 6 1541 1720 1724 1547 1548 1545 + 5 1541 1607 1697 1722 1720 + 7 1541 1545 1542 1546 1608 1609 1607 + 9 1547 1550 2314 1555 2318 1551 2307 1549 1548 + 4 58 2006 1551 2318 + 4 58 2319 1552 2006 + 4 58 2022 1557 2319 + 4 58 2320 1558 2022 + 4 58 2015 1554 2320 + 4 58 2318 1555 2015 + 9 1552 2319 1557 2142 1727 1726 1590 1553 2309 + 9 1554 2317 1556 1563 1725 1728 2144 1558 2320 + 4 16 2142 1557 2022 + 4 16 2143 1727 2142 + 4 16 2026 1593 2143 + 4 16 2145 1594 2026 + 4 16 2144 1728 2145 + 4 16 2022 1558 2144 + 9 1559 1724 1720 1722 1732 1672 2340 1561 2326 + 8 1560 2328 1562 2343 1673 1730 1721 1723 + 4 64 2025 1561 2340 + 4 64 2343 1562 2025 + 4 64 2344 1673 2343 + 4 64 2345 1678 2344 + 4 64 2042 1677 2345 + 4 64 2342 1676 2042 + 4 64 2341 1675 2342 + 4 64 2340 1672 2341 + 7 1563 1723 1721 1737 1738 1729 1725 + 6 1566 1598 1601 1597 1741 1568 + 6 1567 1568 1741 1742 1740 1692 + 8 1569 2190 1580 2180 1579 1747 1570 1571 + 7 1570 1747 1745 1746 1744 1604 1572 + 8 1575 1576 1605 1749 1588 2125 1586 2079 + 4 30 2202 1577 2034 + 4 30 2201 1629 2202 + 4 30 2056 1630 2201 + 4 30 2204 1631 2056 + 4 30 2203 1632 2204 + 4 30 2034 1578 2203 + 4 25 2034 1577 2181 + 4 25 2182 1578 2034 + 4 25 2183 1582 2182 + 4 25 2033 1581 2183 + 4 25 2180 1580 2033 + 4 25 2181 1579 2180 + 8 1577 2202 1629 1748 1745 1747 1579 2181 + 8 1578 2182 1582 1753 1752 1750 1632 2203 + 8 1581 2192 1583 1587 1754 1753 1582 2183 + 8 1584 2081 1585 2127 1589 1751 1754 1587 + 4 12 2127 1585 2049 + 4 12 2128 1589 2127 + 4 12 2020 1622 2128 + 4 12 2126 1623 2020 + 4 12 2125 1588 2126 + 4 12 2049 1586 2125 + 8 1588 1749 1759 1762 1761 2174 1623 2126 + 8 1589 2128 1622 2177 1763 1764 1760 1751 + 7 1590 1726 1766 1768 1620 1592 1591 + 4 21 2161 1593 2026 + 4 21 2162 1624 2161 + 4 21 2032 1756 2162 + 4 21 2165 1755 2032 + 4 21 2164 1757 2165 + 4 21 2163 1625 2164 + 4 21 2026 1594 2163 + 8 1593 2161 1624 1767 1766 1726 1727 2143 + 7 1594 2145 1728 1725 1729 1625 2163 + 7 1595 1612 1611 1617 1618 1613 1596 + 6 1596 1613 1616 1615 1600 1599 + 6 1597 1603 1604 1744 1742 1741 + 6 1605 1606 1614 1769 1759 1749 + 5 1613 1618 1773 1770 1616 + 6 1614 1615 1616 1770 1772 1769 + 6 1617 1619 1621 1771 1773 1618 + 6 1620 1768 1775 1774 1771 1621 + 4 24 2177 1622 2020 + 4 24 2178 1763 2177 + 4 24 2179 1780 2178 + 4 24 2070 1783 2179 + 4 24 2176 1782 2070 + 4 24 2175 1781 2176 + 4 24 2174 1761 2175 + 4 24 2020 1623 2174 + 7 1624 2162 1756 2184 1758 1765 1767 + 7 1625 1729 1738 1785 1786 1757 2164 + 4 32 2054 1626 2209 + 4 32 2211 1627 2054 + 4 32 2212 1635 2211 + 4 32 2056 1631 2212 + 4 32 2210 1630 2056 + 4 32 2209 1636 2210 + 8 1627 2211 1635 1793 1794 1666 1628 2200 + 8 1629 2201 1630 2210 1636 1634 1633 1748 + 8 1631 2204 1632 1750 1795 1793 1635 2212 + 8 1633 1634 1644 1646 1645 1649 1791 1792 + 7 1633 1792 1790 1743 1746 1745 1748 + 6 1637 1639 1640 1709 1710 1641 + 6 1641 1710 1733 1698 1700 1714 + 7 1642 1643 1688 1689 1798 1799 1711 + 4 1644 1647 1650 1646 + 8 1645 1653 2236 1660 2227 1662 1684 1649 + 8 1645 1646 1650 1648 2214 1652 2235 1653 + 6 1649 1684 1686 1687 1693 1791 + 8 1651 2216 1654 1668 1800 1801 1663 2237 + 4 38 2074 1651 2237 + 4 38 2235 1652 2074 + 4 38 2236 1653 2235 + 4 38 2009 1660 2236 + 4 38 2238 1661 2009 + 4 38 2237 1663 2238 + 4 36 2077 1655 2226 + 4 36 2229 1656 2077 + 4 36 2230 1659 2229 + 4 36 2009 1661 2230 + 4 36 2227 1660 2009 + 4 36 2228 1662 2227 + 4 36 2226 1657 2228 + 8 1656 2229 1659 1803 1805 1664 1658 2225 + 6 1657 1685 1686 1684 1662 2228 + 8 1659 2230 1661 2238 1663 1801 1804 1803 + 5 1664 1805 1802 1691 1665 + 8 1666 1794 1797 1808 2264 1670 2245 1667 + 8 1668 1669 2243 1671 2262 1809 1810 1800 + 4 45 2076 1670 2264 + 4 45 2262 1671 2076 + 4 45 2263 1809 2262 + 4 45 2051 1812 2263 + 4 45 2265 1811 2051 + 4 45 2264 1808 2265 + 6 1672 1732 1731 1736 1675 2341 + 6 1673 2344 1678 1817 1816 1730 + 8 1674 1734 1706 1705 1681 2347 1682 2350 + 8 1674 2351 1676 2342 1675 1736 1735 1734 + 4 66 2351 1674 2350 + 4 66 2042 1676 2351 + 4 66 2352 1677 2042 + 4 66 2353 1679 2352 + 4 66 2045 1683 2353 + 4 66 2350 1682 2045 + 8 1677 2352 1679 1820 1818 1817 1678 2345 + 8 1679 2353 1683 2349 1680 1715 1819 1820 + 5 1689 1690 1807 1806 1798 + 5 1690 1691 1802 1821 1807 + 6 1692 1740 1743 1790 1694 1695 + 5 1693 1694 1790 1792 1791 + 5 1696 1701 1700 1698 1699 + 6 1696 1699 1731 1732 1722 1697 + 6 1698 1733 1735 1736 1731 1699 + 7 1702 1707 1711 1799 1813 1814 1713 + 7 1706 1734 1735 1733 1710 1709 1708 + 8 1712 1713 1814 1825 1719 2276 1718 2247 + 8 1715 1716 2249 1717 2278 1829 1830 1819 + 4 48 2278 1717 2027 + 4 48 2279 1829 2278 + 4 48 2061 1826 2279 + 4 48 2277 1827 2061 + 4 48 2276 1719 2277 + 4 48 2027 1718 2276 + 7 1719 1825 1824 1828 2297 1827 2277 + 6 1721 1730 1816 1815 1739 1737 + 6 1737 1739 1834 1833 1785 1738 + 5 1739 1815 1831 1832 1834 + 5 1740 1742 1744 1746 1743 + 7 1750 1752 1836 1835 1823 1796 1795 + 6 1751 1760 1836 1752 1753 1754 + 7 1755 2165 1757 1786 1844 1789 2187 + 4 26 2032 1755 2187 + 4 26 2184 1756 2032 + 4 26 2185 1758 2184 + 4 26 2186 1776 2185 + 4 26 2071 1787 2186 + 4 26 2188 1788 2071 + 4 26 2187 1789 2188 + 6 1758 2185 1776 1840 1842 1765 + 7 1759 1769 1772 1777 1778 1779 1762 + 7 1760 1764 1839 1838 1837 1835 1836 + 6 1761 1762 1779 1846 1781 2175 + 6 1763 2178 1780 1845 1839 1764 + 8 1765 1842 1843 1841 1775 1768 1766 1767 + 7 1770 1773 1771 1774 1847 1777 1772 + 4 1774 1775 1841 1847 + 7 1776 2186 1787 2205 1855 1849 1840 + 7 1777 1847 1841 1843 1860 1859 1778 + 6 1778 1859 1865 1864 1846 1779 + 7 1780 2179 1783 2195 1854 1851 1845 + 8 1781 1846 1864 1862 1784 2194 1782 2176 + 4 28 2070 1782 2194 + 4 28 2195 1783 2070 + 4 28 2196 1854 2195 + 4 28 2024 1853 2196 + 4 28 2193 1852 2024 + 4 28 2194 1784 2193 + 7 1784 1862 1863 1848 2231 1852 2193 + 6 1785 1833 1868 1867 1844 1786 + 4 31 2205 1787 2071 + 4 31 2206 1855 2205 + 4 31 2028 1856 2206 + 4 31 2208 1857 2028 + 4 31 2207 1858 2208 + 4 31 2071 1788 2207 + 9 1788 2188 1789 1844 1867 1869 1870 1858 2207 + 7 1793 1795 1796 1877 1822 1797 1794 + 5 1796 1823 1878 1879 1877 + 8 1797 1822 1881 1880 2291 1811 2265 1808 + 6 1798 1806 1882 1883 1813 1799 + 6 1800 1810 1886 1884 1804 1801 + 7 1802 1805 1803 1804 1884 1885 1821 + 7 1806 1807 1821 1885 1888 1887 1882 + 8 1809 2263 1812 2289 1890 1891 1886 1810 + 4 51 2051 1811 2291 + 4 51 2289 1812 2051 + 4 51 2290 1890 2289 + 4 51 2011 1893 2290 + 4 51 2293 1892 2011 + 4 51 2292 1894 2293 + 4 51 2291 1880 2292 + 6 1813 1883 1895 1824 1825 1814 + 7 1815 1816 1817 1818 1903 1904 1831 + 6 1818 1820 1819 1830 1902 1903 + 6 1822 1877 1879 1906 1907 1881 + 6 1823 1835 1837 1909 1911 1878 + 6 1824 1895 1897 1900 2298 1828 + 8 1826 2300 1901 1912 1902 1830 1829 2279 + 4 53 2300 1826 2061 + 4 53 2301 1901 2300 + 4 53 2029 1899 2301 + 4 53 2299 1898 2029 + 4 53 2298 1900 2299 + 4 53 2297 1828 2298 + 4 53 2061 1827 2297 + 6 1831 1904 1905 1914 1913 1832 + 6 1832 1913 1915 1868 1833 1834 + 5 1837 1838 1916 1917 1909 + 7 1838 1839 1845 1851 1918 1919 1916 + 6 1840 1849 1861 1860 1843 1842 + 4 37 2231 1848 2232 + 4 37 2024 1852 2231 + 4 37 2233 1853 2024 + 4 37 2234 1876 2233 + 4 37 2053 1875 2234 + 4 37 2232 1874 2053 + 9 1848 1863 1866 1850 2217 1873 2239 1874 2232 + 9 1849 1855 2206 1856 2218 1850 1866 1922 1861 + 4 34 2217 1850 2218 + 4 34 2043 1873 2217 + 4 34 2220 1872 2043 + 4 34 2219 1871 2220 + 4 34 2028 1857 2219 + 4 34 2218 1856 2028 + 8 1851 1854 2196 1853 2233 1876 1920 1918 + 7 1857 2208 1858 1870 1921 1871 2219 + 5 1859 1860 1861 1922 1865 + 6 1862 1864 1865 1922 1866 1863 + 6 1867 1868 1915 1924 1923 1869 + 6 1869 1923 1925 1926 1921 1870 + 9 1871 1921 1926 1927 2098 1928 2241 1872 2220 + 4 39 2043 1872 2241 + 4 39 2239 1873 2043 + 4 39 2053 1874 2239 + 4 39 2240 1875 2053 + 4 39 2059 1929 2240 + 4 39 2241 1928 2059 + 9 1875 2240 1929 2096 1930 1931 1920 1876 2234 + 6 1878 1911 1910 1908 1906 1879 + 6 1880 1881 1907 1932 1894 2292 + 7 1882 1887 1889 1896 1897 1895 1883 + 7 1884 1886 1891 1936 1934 1888 1885 + 5 1887 1888 1934 1933 1889 + 4 1889 1933 1935 1896 + 8 1890 2290 1893 2310 1937 1938 1936 1891 + 8 1892 2293 1894 1932 1942 1943 1939 2312 + 4 56 2011 1892 2312 + 4 56 2310 1893 2011 + 4 56 2311 1937 2310 + 4 56 2041 1941 2311 + 4 56 2313 1940 2041 + 4 56 2312 1939 2313 + 9 1896 1935 1944 1947 2321 1898 2299 1900 1897 + 4 59 2029 1898 2321 + 4 59 2323 1899 2029 + 4 59 2324 1948 2323 + 4 59 2047 1946 2324 + 4 59 2322 1945 2047 + 4 59 2321 1947 2322 + 8 1899 2323 1948 1953 1951 1912 1901 2301 + 7 1902 1912 1951 1954 1905 1904 1903 + 5 1905 1954 1952 1950 1914 + 7 1906 1908 1956 1955 1942 1932 1907 + 5 1908 1910 1957 1959 1956 + 6 1909 1917 1958 1957 1910 1911 + 6 1913 1914 1950 1949 1924 1915 + 6 1916 1919 1960 1962 1958 1917 + 6 1918 1920 1931 1961 1960 1919 + 7 1923 1924 1949 1965 1964 1963 1925 + 8 1925 1963 1969 2117 1966 2099 1927 1926 + 4 5 2098 1927 2099 + 4 5 2059 1928 2098 + 4 5 2096 1929 2059 + 4 5 2097 1930 2096 + 4 5 2018 1967 2097 + 4 5 2099 1966 2018 + 7 1930 2097 1967 2115 1968 1961 1931 + 7 1933 1934 1936 1938 1970 1944 1935 + 8 1937 2311 1941 2333 1972 1973 1970 1938 + 7 1939 1943 1976 1975 2335 1940 2313 + 4 62 2041 1940 2335 + 4 62 2333 1941 2041 + 4 62 2334 1972 2333 + 4 62 2063 1978 2334 + 4 62 2336 1977 2063 + 4 62 2335 1975 2336 + 6 1942 1955 1981 1982 1976 1943 + 8 1944 1970 1973 1971 2329 1945 2322 1947 + 4 61 2047 1945 2329 + 4 61 2331 1946 2047 + 4 61 2332 1974 2331 + 4 61 2058 1980 2332 + 4 61 2330 1979 2058 + 4 61 2329 1971 2330 + 8 1946 2331 1974 1984 1983 1953 1948 2324 + 6 1949 1950 1952 1985 1987 1965 + 7 1951 1953 1983 1986 1985 1952 1954 + 6 1955 1956 1959 1990 1988 1981 + 6 1957 1958 1962 1989 1990 1959 + 9 1960 1961 1968 2116 1992 2137 1995 1989 1962 + 7 1963 1964 1993 2139 1991 2118 1969 + 6 1964 1965 1987 1994 2140 1993 + 4 10 2018 1966 2117 + 4 10 2115 1967 2018 + 4 10 2116 1968 2115 + 4 10 2036 1992 2116 + 4 10 2118 1991 2036 + 4 10 2117 1969 2118 + 8 1971 1973 1972 2334 1978 2337 1979 2330 + 8 1974 2332 1980 2339 1996 2152 1999 1984 + 9 1975 1976 1982 1998 2150 1997 2338 1977 2336 + 4 63 2063 1977 2338 + 4 63 2337 1978 2063 + 4 63 2058 1979 2337 + 4 63 2339 1980 2058 + 4 63 2069 1996 2339 + 4 63 2338 1997 2069 + 8 1981 1988 2004 2157 2001 2151 1998 1982 + 8 1983 1984 1999 2153 2000 2159 2005 1986 + 8 1985 1986 2005 2160 2002 2141 1994 1987 + 8 1988 1990 1989 1995 2138 2003 2158 2004 + 4 15 2036 1991 2139 + 4 15 2137 1992 2036 + 4 15 2138 1995 2137 + 4 15 2044 2003 2138 + 4 15 2141 2002 2044 + 4 15 2140 1994 2141 + 4 15 2139 1993 2140 + 4 18 2152 1996 2069 + 4 18 2153 1999 2152 + 4 18 2048 2000 2153 + 4 18 2151 2001 2048 + 4 18 2150 1998 2151 + 4 18 2069 1997 2150 + 4 20 2159 2000 2048 + 4 20 2160 2005 2159 + 4 20 2044 2002 2160 + 4 20 2158 2003 2044 + 4 20 2157 2004 2158 + 4 20 2048 2001 2157 + +395 + 12 0 1 2 3 4 5 2153 2154 2155 2156 2157 2158 + 12 6 7 8 9 10 11 2055 2056 2057 2058 2059 2060 + 12 12 13 14 15 16 2064 2065 2066 2067 2068 2069 6 + 12 17 18 19 20 21 22 2025 2026 2027 2028 2029 2030 + 14 23 24 25 26 27 28 29 2019 2020 2021 2022 2023 2024 17 + 12 30 31 32 33 34 35 2620 2621 2622 2623 2624 2625 + 12 36 37 38 39 40 2049 2050 2051 2052 2053 2054 7 + 12 41 42 43 44 45 2041 2042 2043 2044 2045 2046 23 + 12 46 47 48 49 50 2139 2140 2141 2142 2143 2144 0 + 13 51 52 53 54 55 56 2070 2071 2072 2073 2074 2075 12 + 12 57 58 59 60 61 2652 2653 2654 2655 2656 2657 30 + 16 62 63 64 65 66 67 68 2083 2084 2085 2086 2087 2088 2089 2090 51 + 12 69 70 71 72 73 2374 2375 2376 2377 2378 2379 1 + 12 74 75 76 77 78 2187 2188 2189 2190 2191 2192 62 + 12 79 80 81 82 83 2196 2197 2198 2199 2200 2201 74 + 15 84 85 86 87 88 89 90 2671 2672 2673 2674 2675 2676 2677 57 + 13 91 92 93 94 95 96 97 2336 2337 2338 2339 2340 2341 + 13 98 99 100 101 102 103 2102 2103 2104 2105 2106 2107 18 + 13 104 105 106 107 108 109 110 2678 2679 2680 2681 2682 2683 + 12 111 112 113 114 115 116 2238 2239 2240 2241 2242 2243 + 12 117 118 119 120 2684 2685 2686 2687 2688 2689 84 104 + 14 121 122 123 124 125 126 2383 2384 2385 2386 2387 2388 2389 91 + 13 127 128 129 130 131 2124 2125 2126 2127 2128 2129 36 41 + 13 132 133 134 135 136 2133 2134 2135 2136 2137 2138 46 79 + 16 137 138 139 140 141 142 143 2400 2401 2402 2403 2404 2405 2406 2407 69 + 12 144 145 146 147 148 149 2364 2365 2366 2367 2368 2369 + 14 150 151 152 153 154 155 2491 2492 2493 2494 2495 2496 2497 121 + 12 156 157 158 159 2146 2147 2148 2149 2150 2151 47 144 + 12 160 161 162 163 164 2511 2512 2513 2514 2515 2516 137 + 12 165 166 167 168 169 2231 2232 2233 2234 2235 2236 111 + 12 170 171 172 173 174 2358 2359 2360 2361 2362 2363 145 + 12 175 176 177 178 179 2519 2520 2521 2522 2523 2524 150 + 13 180 181 182 183 184 2410 2411 2412 2413 2414 2415 165 170 + 13 185 186 187 188 189 190 2246 2247 2248 2249 2250 2251 112 + 13 191 192 193 194 195 196 2568 2569 2570 2571 2572 2573 175 + 14 197 198 199 200 201 202 2223 2224 2225 2226 2227 2228 2229 98 + 14 203 204 205 206 207 208 2435 2436 2437 2438 2439 2440 2441 197 + 13 209 210 211 212 213 214 2560 2561 2562 2563 2564 2565 160 + 12 215 216 217 218 2429 2430 2431 2432 2433 2434 185 203 + 12 219 220 221 2581 2582 2583 2584 2585 2586 31 191 209 + 12 222 223 224 225 226 2252 2253 2254 2255 2256 2257 113 + 13 227 228 229 230 231 232 233 2303 2304 2305 2306 2307 2308 + 12 234 235 236 237 238 2077 2078 2079 2080 2081 2082 13 + 13 239 240 241 242 243 244 2032 2033 2034 2035 2036 2037 19 + 12 245 246 247 248 249 250 2174 2175 2176 2177 2178 2179 + 12 251 252 253 254 255 2448 2449 2450 2451 2452 2453 222 + 15 256 257 258 259 260 261 2095 2096 2097 2098 2099 2100 2101 234 245 + 14 262 263 264 265 266 267 2112 2113 2114 2115 2116 2117 2118 239 + 12 268 269 270 271 272 2477 2478 2479 2480 2481 2482 227 + 14 273 274 275 276 277 278 2214 2215 2216 2217 2218 2219 2220 262 + 12 279 280 281 282 283 2275 2276 2277 2278 2279 2280 273 + 14 284 285 286 287 288 289 2534 2535 2536 2537 2538 2539 2540 251 + 12 290 291 292 293 294 2285 2286 2287 2288 2289 2290 228 + 14 295 296 297 298 299 300 2548 2549 2550 2551 2552 2553 2554 268 + 13 301 302 303 304 305 306 2166 2167 2168 2169 2170 2171 246 + 13 307 308 309 310 311 312 2160 2161 2162 2163 2164 2165 301 + 12 313 314 315 316 317 2596 2597 2598 2599 2600 2601 284 + 13 318 319 320 321 322 323 324 2309 2310 2311 2312 2313 2314 + 12 325 326 327 2328 2329 2330 2331 2332 2333 92 307 318 + 12 328 329 330 331 332 2603 2604 2605 2606 2607 2608 295 + 12 333 334 335 336 337 2315 2316 2317 2318 2319 2320 319 + 14 338 339 340 341 342 343 344 2638 2639 2640 2641 2642 2643 328 + 13 345 346 347 348 349 350 2630 2631 2632 2633 2634 2635 313 + 12 351 352 353 2661 2662 2663 2664 2665 2666 105 338 345 + 16 354 355 356 357 358 359 360 2344 2345 2346 2347 2348 2349 2350 2351 333 + 12 361 362 363 364 365 2296 2297 2298 2299 2300 2301 290 + 12 366 367 368 369 2458 2459 2460 2461 2462 2463 354 361 + 13 370 371 372 373 374 2269 2270 2271 2272 2273 2274 279 291 + 8 375 376 377 378 2031 20 24 99 + 11 379 380 381 382 383 384 385 2047 25 42 375 + 11 386 387 388 389 390 391 392 2062 8 14 52 + 9 393 394 395 396 397 2091 53 63 386 + 12 398 399 400 401 402 403 404 405 2061 9 37 387 + 11 406 407 408 409 410 411 2108 100 198 376 379 + 11 412 413 414 415 416 417 418 419 2131 380 406 + 11 420 421 422 423 424 425 2121 43 127 381 412 + 10 426 427 428 429 430 2123 38 128 398 420 + 11 431 432 433 434 435 436 437 2185 413 421 426 + 9 438 439 440 441 442 443 2264 414 431 + 9 444 445 446 447 448 449 2186 432 438 + 10 450 451 452 453 454 455 456 2202 80 132 + 9 457 458 459 460 2145 48 133 156 450 + 12 461 462 463 464 465 466 467 2184 399 427 433 444 + 10 468 469 470 471 472 473 2182 64 393 461 + 9 474 475 476 2183 388 394 400 462 468 + 12 477 478 479 480 481 482 483 484 2193 65 75 469 + 10 485 486 487 488 489 2211 76 81 451 477 + 11 490 491 492 493 494 495 496 497 2237 166 180 + 10 498 499 500 501 502 2230 114 167 186 490 + 6 503 504 505 2424 491 498 + 9 506 507 508 509 2426 187 215 499 503 + 12 510 511 512 513 514 515 516 2258 199 204 407 415 + 10 517 518 519 520 521 522 2260 416 439 510 + 10 523 524 525 526 527 528 529 2265 440 517 + 9 530 531 532 533 534 2266 441 445 523 + 10 535 536 537 538 539 540 541 2394 478 485 + 10 542 543 544 545 2353 446 463 470 479 535 + 10 546 547 548 549 550 2354 447 530 536 542 + 12 551 552 553 554 555 556 557 558 2356 452 486 537 + 12 559 560 561 562 563 564 2355 146 157 453 457 551 + 10 565 566 567 568 569 570 2417 171 181 492 + 10 571 572 573 574 2370 147 172 552 559 565 + 8 575 576 577 578 2487 538 546 553 + 12 579 580 581 582 583 584 585 2420 554 566 571 575 + 12 586 587 588 589 590 591 2419 493 504 506 567 579 + 11 592 593 594 595 596 597 598 2427 518 524 586 + 10 599 600 601 602 2468 525 531 547 576 580 + 8 603 604 2469 526 581 587 592 599 + 12 605 606 607 608 609 610 2425 205 216 507 588 593 + 10 611 612 613 614 2443 206 511 519 594 605 + 9 615 616 617 618 619 2038 21 26 240 + 9 620 621 622 623 2040 27 44 382 615 + 10 624 625 626 627 628 2048 10 39 389 401 + 10 629 630 631 632 633 634 635 2094 235 256 + 13 636 637 638 639 640 641 2063 11 15 236 390 624 629 + 11 642 643 644 645 646 647 648 2110 241 263 616 + 12 649 650 651 652 653 654 2120 40 129 402 428 625 + 11 655 656 657 658 2122 45 130 383 422 620 649 + 10 659 660 661 662 663 2205 626 630 636 650 + 13 664 665 666 667 668 669 670 671 2130 617 621 642 655 + 10 672 673 674 675 676 2267 651 656 659 664 + 10 677 678 679 680 681 682 683 2206 660 672 + 9 684 685 686 687 688 2293 665 673 677 + 9 689 690 691 692 693 694 2180 247 302 + 10 695 696 697 698 699 700 2172 303 308 689 + 10 701 702 703 704 705 2327 309 320 325 695 + 11 706 707 708 709 710 711 712 2207 631 661 678 + 11 713 714 715 716 717 2204 248 257 632 690 706 + 10 718 719 720 721 722 2326 691 696 707 713 + 11 723 724 725 726 727 728 729 2261 643 666 684 + 10 730 731 732 733 734 2221 264 274 644 723 + 9 735 736 737 738 739 2222 275 724 730 + 11 740 741 742 743 744 745 746 2292 679 708 718 + 7 747 748 749 750 751 2470 740 + 10 752 753 754 755 756 757 2291 292 362 370 + 11 758 759 760 761 762 763 764 2281 280 371 752 + 10 765 766 767 768 769 2283 276 281 735 758 + 9 770 771 772 773 774 2421 725 736 765 + 11 775 776 777 778 779 780 2294 680 685 741 747 + 9 781 782 783 784 2295 686 726 770 775 + 10 785 786 787 788 789 790 791 2325 719 742 + 10 792 793 794 795 796 2324 697 701 720 785 + 9 797 798 799 800 2321 321 334 702 792 + 13 801 802 803 804 805 806 807 2342 335 355 786 793 797 + 10 808 809 810 811 812 2471 743 748 787 801 + 12 813 814 815 816 817 818 819 2422 749 771 776 781 + 11 820 821 822 823 824 825 2456 363 366 753 759 + 11 826 827 828 829 830 2474 760 766 772 813 820 + 10 831 832 833 834 835 2472 750 808 814 826 + 10 836 837 838 839 840 2454 356 802 809 831 + 9 841 842 2457 357 367 821 827 832 836 + 10 843 844 845 846 2076 16 54 237 391 637 + 8 847 848 849 2092 55 66 395 843 + 10 850 851 852 853 2093 238 258 633 638 844 + 9 854 855 856 857 2132 2 49 134 458 + 9 858 859 860 861 862 2159 304 310 698 + 9 863 864 865 866 2173 249 305 692 858 + 12 867 868 869 870 871 872 2181 67 396 471 480 847 + 8 873 874 875 2194 68 77 481 867 + 9 876 877 878 879 2195 82 135 454 854 + 12 880 881 882 883 884 885 2203 250 259 693 714 863 + 13 886 887 888 889 890 891 892 2208 639 845 848 850 868 + 9 893 894 895 896 2209 260 851 880 886 + 14 897 898 899 900 901 902 2210 78 83 455 482 487 873 876 + 9 903 904 905 906 907 2393 869 874 897 + 10 908 909 910 911 912 2392 870 887 893 903 + 9 913 914 915 916 917 2212 881 894 908 + 9 918 919 920 921 922 2323 864 882 913 + 11 923 924 925 926 927 2334 93 311 326 703 859 + 12 928 929 930 931 932 933 934 2357 3 70 855 877 + 11 935 936 937 938 939 940 941 2380 71 138 928 + 13 942 943 944 945 946 947 948 949 2382 860 865 918 923 + 11 950 951 952 953 954 955 2390 94 122 924 942 + 9 956 957 958 959 960 2408 123 151 950 + 12 961 962 963 964 965 966 967 2395 878 898 929 935 + 11 968 969 970 971 972 973 974 975 2396 904 909 + 10 976 977 978 979 980 2397 899 905 961 968 + 10 981 982 983 984 985 2398 910 914 919 969 + 10 986 987 988 989 990 991 2399 920 943 981 + 10 992 993 994 995 996 997 2499 936 962 976 + 11 998 999 1000 1001 1002 1003 2503 944 951 956 986 + 9 1004 1005 1006 1007 1008 2498 152 957 998 + 10 1009 1010 1011 1012 1013 1014 2501 139 937 992 + 12 1015 1016 1017 1018 1019 1020 2504 970 977 982 987 993 + 9 1021 1022 1023 1024 1025 2505 988 999 1015 + 10 1026 1027 1028 1029 1030 1031 2506 153 176 1004 + 11 1032 1033 1034 1035 1036 1037 2507 994 1000 1016 1021 + 8 1038 1039 1040 2559 1001 1005 1026 1032 + 11 1041 1042 1043 1044 1045 1046 1047 2508 995 1009 1033 + 10 1048 1049 1050 1051 1052 1053 1054 2517 161 210 + 10 1055 1056 1057 1058 2510 140 162 1010 1041 1048 + 10 1059 1060 1061 1062 1063 2566 192 211 219 1049 + 12 1064 1065 1066 1067 1068 1069 2567 177 193 1027 1038 1059 + 10 1070 1071 1072 1073 1074 2576 1034 1039 1042 1064 + 10 1075 1076 1077 2577 1043 1050 1055 1060 1065 1070 + 11 1078 1079 1080 1081 2039 22 28 101 242 377 618 + 10 1082 1083 1084 1085 2109 102 200 408 512 1078 + 8 1086 1087 1088 2111 243 265 645 1079 + 9 1089 1090 1091 1092 1093 2119 1080 1082 1086 + 9 1094 1095 1096 1097 2213 266 277 731 737 + 9 1098 1099 1100 1101 2259 201 513 1083 1089 + 9 1102 1103 1104 1105 2245 115 188 223 500 + 14 1106 1107 1108 1109 1110 1111 1112 2262 267 646 732 1087 1090 1094 + 10 1113 1114 1115 1116 1117 1118 2263 1091 1098 1106 + 8 1119 1120 1121 1122 2282 282 372 761 + 13 1123 1124 1125 1126 1127 2268 278 283 738 762 767 1095 1119 + 10 1128 1129 1130 1131 2284 229 293 373 754 1120 + 12 1132 1133 1134 1135 1136 1137 1138 2423 1096 1107 1113 1123 + 10 1139 1140 1141 1142 2428 189 217 508 606 1102 + 12 1143 1144 1145 1146 1147 1148 2442 202 207 514 611 1099 + 11 1149 1150 1151 1152 2444 208 218 607 612 1139 1143 + 10 1153 1154 1155 1156 1157 1158 2445 1100 1114 1144 + 8 1159 1160 1161 1162 1163 2466 1115 1132 + 11 1164 1165 1166 1167 1168 1169 2447 224 252 1103 1140 + 10 1170 1171 1172 1173 1174 2473 1121 1124 1128 1133 + 9 1175 1176 1177 1178 1179 2467 1116 1153 1159 + 11 1180 1181 1182 1183 1184 1185 2475 230 269 1129 1170 + 9 1186 1187 1188 1189 1190 2483 270 296 1180 + 10 1191 1192 1193 1194 1195 1196 2529 1134 1160 1171 + 11 1197 1198 1199 1200 1201 1202 1203 2530 1141 1149 1164 + 11 1204 1205 1206 1207 1208 2531 1145 1150 1154 1175 1197 + 11 1209 1210 1211 1212 1213 1214 2532 1161 1176 1191 1204 + 12 1215 1216 1217 1218 1219 1220 1221 2533 253 285 1165 1198 + 12 1222 1223 1224 1225 1226 1227 1228 2541 1172 1181 1186 1192 + 10 1229 1230 1231 1232 1233 1234 2590 1193 1209 1222 + 10 1235 1236 1237 1238 1239 2546 297 1187 1223 1229 + 12 1240 1241 1242 1243 1244 1245 1246 2591 1199 1205 1210 1215 + 7 1247 1248 1249 2592 1211 1230 1240 + 7 1250 1251 1252 1253 2593 1231 1247 + 11 1254 1255 1256 1257 1258 1259 2594 286 314 1216 1241 + 12 1260 1261 1262 1263 1264 1265 2602 298 329 1232 1235 1250 + 15 1266 1267 1268 1269 1270 1271 1272 1273 1274 2627 1242 1248 1251 1254 1260 + 11 1275 1276 1277 1278 1279 1280 2628 315 346 1255 1266 + 10 1281 1282 1283 1284 2637 330 339 1261 1267 1275 + 9 1285 1286 1287 2658 340 347 351 1276 1281 + 11 1288 1289 1290 2152 4 50 158 459 560 856 930 + 11 1291 1292 1293 2244 116 168 225 494 501 1104 1166 + 12 1294 1295 1296 1297 1298 1299 1300 2371 148 173 561 572 + 11 1301 1302 1303 1304 2372 149 159 562 931 1288 1294 + 10 1305 1306 1307 2373 5 72 932 938 1289 1301 + 11 1308 1309 1310 1311 1312 2381 73 141 939 1011 1305 + 10 1313 1314 1315 1316 1317 2416 169 182 495 1291 + 12 1318 1319 1320 1321 1322 2418 174 183 568 573 1295 1313 + 12 1323 1324 1325 1326 1327 2446 226 254 1167 1217 1292 1314 + 12 1328 1329 1330 1331 1332 1333 1334 1335 1336 2488 1296 1318 + 10 1337 1338 1339 1340 2489 1297 1302 1306 1308 1328 + 10 1341 1342 1343 1344 1345 1346 2500 1309 1329 1337 + 10 1347 1348 1349 1350 2502 142 1012 1056 1310 1341 + 9 1351 1352 1353 2509 143 163 1051 1057 1347 + 12 1354 1355 1356 1357 1358 1359 1360 2526 1315 1319 1323 1330 + 8 1361 1362 1363 1364 1365 2527 1331 1354 + 10 1366 1367 1368 1369 2528 255 287 1218 1324 1355 + 10 1370 1371 1372 1373 1374 1375 2544 1356 1361 1366 + 11 1376 1377 1378 1379 1380 1381 1382 2545 1332 1342 1362 + 9 1383 1384 1385 1386 1387 2588 1363 1370 1376 + 8 1388 1389 1390 1391 1392 2557 1343 1377 + 11 1393 1394 1395 1396 1397 1398 2558 1344 1348 1351 1388 + 11 1399 1400 1401 1402 1403 2574 164 212 1052 1352 1393 + 12 1404 1405 1406 1407 1408 1409 2587 32 213 220 1061 1399 + 10 1410 1411 1412 1413 2589 288 1219 1256 1367 1371 + 10 1414 1415 1416 1417 2595 289 316 1257 1277 1410 + 11 1418 1419 1420 1421 1422 1423 2612 1372 1383 1411 1414 + 9 1424 1425 1426 1427 1428 1429 2613 1384 1418 + 8 1430 1431 1432 2614 1378 1385 1389 1424 + 12 1433 1434 1435 1436 1437 1438 1439 1440 2616 1390 1394 1430 + 10 1441 1442 1443 1444 1445 2617 1395 1400 1404 1433 + 7 1446 1447 2626 33 58 1405 1441 + 9 1448 1449 1450 1451 2629 317 348 1278 1415 + 10 1452 1453 1454 1455 1456 1457 2636 1416 1419 1448 + 11 1458 1459 1460 1461 1462 1463 1464 2647 1420 1425 1452 + 9 1465 1466 1467 1468 2648 1426 1431 1434 1458 + 12 1469 1470 1471 1472 1473 2649 59 85 1435 1442 1446 1465 + 10 1474 1475 1476 2660 106 349 352 1285 1449 1453 + 11 1477 1478 1479 1480 1481 2667 107 117 1454 1459 1474 + 10 1482 1483 1484 2670 86 118 1460 1466 1469 1477 + 9 1485 1486 1487 2302 231 294 364 755 1130 + 10 1488 1489 1490 1491 1492 2322 322 336 798 803 + 11 1493 1494 1495 1496 2335 95 323 327 704 925 1488 + 8 1497 1498 1499 2391 96 124 952 1493 + 10 1500 1501 1502 1503 1504 2343 337 358 804 1489 + 11 1505 1506 1507 1508 1509 1510 2352 1490 1494 1497 1500 + 11 1511 1512 1513 1514 1515 2409 125 953 958 1498 1505 + 9 1516 1517 1518 1519 2455 359 805 837 1501 + 9 1520 1521 1522 1523 1524 2484 1502 1506 1516 + 12 1525 1526 1527 1528 1529 2464 360 368 822 838 841 1517 + 11 1530 1531 1532 1533 2465 365 369 756 823 1485 1525 + 11 1534 1535 1536 1537 2476 232 271 1182 1188 1486 1530 + 12 1538 1539 1540 1541 1542 1543 1544 1545 2485 1507 1511 1520 + 9 1546 1547 1548 1549 1550 1551 2486 1521 1538 + 11 1552 1553 1554 1555 2490 126 154 959 1006 1028 1512 + 10 1556 1557 1558 1559 1560 1561 2518 1513 1539 1552 + 10 1562 1563 1564 1565 2525 155 178 1029 1553 1556 + 11 1566 1567 1568 1569 1570 1571 2542 1518 1522 1526 1546 + 11 1572 1573 1574 1575 1576 1577 2543 1527 1531 1534 1566 + 12 1578 1579 1580 1581 1582 2547 272 299 1189 1236 1535 1572 + 10 1583 1584 1585 1586 1587 1588 1589 2555 1547 1567 + 9 1590 1591 1592 1593 2556 1540 1548 1557 1583 + 11 1594 1595 1596 1597 1598 2575 179 194 1030 1066 1562 + 11 1599 1600 1601 1602 1603 1604 1605 2578 1558 1563 1590 + 9 1606 1607 1608 1609 1610 2579 1564 1594 1599 + 11 1611 1612 1613 2580 34 195 221 1062 1406 1595 1606 + 8 1614 1615 1616 1617 2615 1584 1591 1600 + 12 1618 1619 1620 1621 1622 1623 2609 300 331 1237 1262 1578 + 11 1624 1625 1626 1627 1628 2610 1568 1573 1579 1585 1618 + 10 1629 1630 1631 1632 1633 1634 2611 1586 1614 1624 + 11 1635 1636 1637 1638 1639 1640 1641 2618 1601 1607 1615 + 12 1642 1643 2619 35 60 1407 1443 1447 1470 1608 1611 1635 + 10 1644 1645 1646 1647 2644 332 341 1263 1282 1619 + 12 1648 1649 1650 1651 1652 1653 1654 1655 2645 1616 1629 1636 + 11 1656 1657 1658 1659 1660 2646 1620 1625 1630 1644 1648 + 9 1661 1662 1663 2650 61 87 1471 1637 1642 + 7 1664 1665 2651 88 1638 1649 1661 + 10 1666 1667 1668 2659 108 342 353 1286 1475 1645 + 11 1669 1670 1671 1672 2668 109 119 1478 1646 1656 1666 + 11 1673 1674 2669 89 120 1479 1482 1650 1657 1664 1669 + 18 1675 1676 1677 29 103 244 378 384 409 619 622 647 667 1081 1084 1088 1092 1108 + 13 1678 1679 1680 1681 1682 385 410 417 423 623 657 668 1675 + 14 1683 1684 56 392 397 403 472 474 627 640 846 849 871 888 + 11 1685 1686 1687 1688 1689 404 429 434 448 464 652 + 20 1690 1691 1692 1693 1694 1695 405 465 475 628 634 641 653 662 681 709 852 889 1683 1685 + 16 1696 1697 1698 1699 1700 1701 261 635 710 715 853 883 890 895 915 1690 + 18 1702 1703 1704 1705 1706 411 418 515 520 1085 1093 1101 1109 1117 1146 1155 1676 1678 + 13 1707 1708 1709 1710 1711 648 669 727 733 1110 1677 1679 1702 + 14 1712 1713 1714 1715 1716 419 424 435 442 521 527 532 1680 1703 + 21 1717 1718 1719 1720 1721 1722 131 425 430 436 654 658 663 670 674 682 1681 1686 1691 1707 1712 + 15 1723 1724 1725 1726 1727 1728 675 683 687 711 744 777 1692 1696 1717 + 13 1729 1730 1731 1732 671 676 688 728 778 782 1708 1718 1723 + 14 1733 1734 1735 1736 1737 1738 1739 1740 1682 1704 1709 1713 1719 1729 + 18 1741 1742 1743 1744 1745 306 694 699 716 721 788 794 861 866 884 921 945 1697 + 15 1746 1747 312 324 700 705 795 799 862 926 946 1491 1495 1508 1741 + 16 1748 1749 1750 1751 1752 437 443 449 466 533 543 548 1687 1714 1720 1733 + 17 1753 1754 1755 136 456 460 488 555 563 857 879 900 933 963 1290 1298 1303 + 22 1756 1757 1758 1759 1760 467 473 476 483 539 544 872 875 891 901 906 911 971 1684 1688 1693 1748 + 12 1761 1762 1763 1764 1765 1689 1694 1698 1721 1724 1749 1756 + 16 1766 1767 1768 1769 1770 484 489 540 556 902 907 964 972 978 1753 1757 + 17 1771 1772 1773 1774 1775 1776 1777 1778 712 717 722 745 789 1699 1725 1742 1761 + 15 1779 1780 1781 1782 1783 1784 885 916 922 947 983 989 1700 1743 1771 + 14 1785 1786 892 896 912 917 973 984 1695 1701 1758 1762 1772 1779 + 14 1787 1788 1789 1790 1791 184 496 569 582 589 1316 1320 1325 1357 + 19 1792 1793 1794 1795 1796 729 734 739 768 773 783 815 1097 1111 1125 1135 1710 1730 1734 + 21 1797 1798 1799 1800 190 497 502 505 509 590 595 608 1105 1142 1151 1168 1200 1293 1317 1326 1787 + 18 1801 1802 1803 1804 1805 1806 516 522 528 596 609 613 1147 1156 1705 1715 1735 1797 + 16 1807 1808 1809 1810 1112 1118 1136 1157 1162 1177 1206 1706 1711 1736 1792 1801 + 15 1811 1812 1813 1814 1815 529 534 549 597 600 603 1716 1737 1750 1802 + 16 1816 1817 1818 1819 1820 1821 1822 1823 1722 1726 1731 1738 1751 1763 1773 1811 + 16 1824 1825 1826 1827 1828 1829 746 751 779 790 810 816 833 1727 1774 1816 + 18 1830 1831 1832 233 374 757 763 824 828 1122 1126 1131 1173 1183 1487 1532 1536 1574 + 17 1833 1834 1835 1836 764 769 774 817 829 1127 1137 1174 1184 1194 1224 1793 1830 + 17 1837 1838 1839 1840 1841 1842 1843 780 784 818 1728 1732 1739 1794 1817 1824 1833 + 12 1844 1845 1846 1847 1848 1740 1795 1803 1807 1812 1818 1837 + 19 1849 1850 1851 1852 791 796 800 806 811 1492 1503 1509 1523 1541 1744 1746 1775 1780 1825 + 16 1853 1854 1855 97 927 948 954 1496 1499 1510 1514 1542 1745 1747 1781 1849 + 18 1856 1857 1858 1859 1860 807 812 834 839 1504 1519 1524 1528 1543 1549 1569 1826 1850 + 18 1861 1862 1863 819 825 830 835 840 842 1529 1533 1570 1575 1827 1831 1834 1838 1856 + 19 1864 1865 1866 1867 1868 1869 541 545 550 557 577 583 601 1752 1759 1764 1766 1813 1819 + 18 1870 1871 1872 1873 1874 558 564 570 574 578 584 1299 1321 1333 1754 1767 1788 1864 + 15 1875 1876 1877 934 940 965 1300 1304 1307 1311 1334 1338 1755 1768 1870 + 14 1878 1879 1880 941 966 996 1013 1044 1312 1339 1345 1349 1396 1875 + 18 1881 1882 1883 1884 1885 949 955 960 990 1002 1007 1022 1515 1544 1554 1559 1782 1853 + 16 1886 1887 1888 1889 1890 1891 974 979 1017 1760 1765 1769 1776 1785 1820 1865 + 15 1892 1893 1894 1895 1896 1897 1777 1783 1821 1828 1851 1854 1857 1881 1886 + 15 1898 1899 1900 967 980 997 1018 1035 1045 1770 1866 1871 1876 1878 1887 + 12 1901 975 985 991 1019 1023 1778 1784 1786 1882 1888 1892 + 19 1902 1903 1904 1905 1906 1907 1908 585 591 598 602 604 1789 1798 1804 1814 1844 1867 1872 + 11 1909 1910 1911 1322 1335 1358 1364 1379 1790 1873 1902 + 15 1912 1913 1914 1915 1169 1201 1220 1327 1359 1368 1373 1791 1799 1903 1909 + 15 1916 1917 1918 1919 1138 1163 1178 1195 1212 1225 1796 1808 1835 1839 1845 + 15 1920 1921 610 614 1148 1152 1158 1202 1207 1243 1800 1805 1809 1904 1912 + 17 1922 1923 1924 1925 1926 1927 1179 1208 1213 1244 1806 1810 1846 1905 1913 1916 1920 + 17 1928 1929 1930 1931 1932 1933 1934 1935 1815 1822 1840 1847 1868 1889 1893 1906 1922 + 12 1936 1937 1938 1939 1940 1823 1829 1841 1858 1861 1894 1928 + 19 1941 1942 1943 1944 1945 1185 1190 1226 1238 1537 1576 1580 1626 1832 1836 1842 1862 1917 1936 + 13 1946 1947 1948 1949 1950 1951 1843 1848 1918 1923 1929 1937 1941 + 18 1952 1953 1954 1955 1956 1545 1550 1560 1587 1592 1602 1852 1855 1859 1883 1895 1930 1938 + 15 1957 1958 1959 1551 1571 1577 1588 1627 1631 1860 1863 1939 1942 1946 1952 + 21 1960 1961 1962 1963 1964 1336 1340 1346 1380 1391 1397 1436 1869 1874 1877 1879 1890 1898 1907 1910 1931 + 21 1965 1966 1967 1968 1003 1008 1024 1031 1036 1040 1067 1071 1555 1561 1565 1596 1603 1609 1884 1896 1953 + 19 1969 1970 1971 1972 1014 1046 1053 1058 1072 1075 1350 1353 1398 1401 1437 1444 1880 1899 1960 + 18 1973 1974 1975 1020 1025 1037 1047 1073 1885 1891 1897 1900 1901 1932 1954 1961 1965 1969 + 12 1976 196 214 1054 1063 1068 1076 1402 1408 1597 1612 1970 + 18 1977 1978 1979 1980 1981 1360 1365 1374 1381 1386 1421 1427 1908 1911 1914 1924 1933 1962 + 16 1982 1983 1984 1203 1221 1245 1258 1268 1369 1375 1412 1422 1915 1921 1925 1977 + 15 1985 1986 1196 1214 1227 1233 1246 1249 1252 1269 1919 1926 1943 1947 1982 + 14 1987 1988 1989 1228 1234 1239 1253 1264 1270 1581 1621 1944 1948 1985 + 14 1990 1991 1992 1993 1994 1995 1271 1927 1934 1949 1978 1983 1986 1987 + 18 1996 1997 1998 1999 2000 1382 1387 1392 1428 1432 1438 1461 1467 1963 1971 1973 1979 1990 + 18 2001 2002 2003 2004 2005 1632 1651 1935 1940 1950 1955 1957 1964 1966 1974 1980 1991 1996 + 15 2006 2007 2008 1582 1622 1628 1633 1652 1658 1945 1951 1958 1988 1992 2001 + 13 2009 2010 1589 1593 1604 1617 1634 1639 1653 1956 1959 1967 2002 + 23 2011 1069 1074 1077 1403 1409 1439 1445 1472 1598 1605 1610 1613 1640 1643 1662 1968 1972 1975 1976 1997 2003 2009 + 17 2012 2013 2014 1259 1272 1279 1413 1417 1423 1429 1450 1455 1462 1981 1984 1993 1998 + 15 2015 2016 343 1265 1273 1283 1623 1647 1659 1667 1670 1989 1994 2006 2012 + 16 2017 2018 1456 1463 1480 1483 1654 1660 1671 1673 1995 1999 2004 2007 2013 2015 + 17 90 1440 1464 1468 1473 1484 1641 1655 1663 1665 1674 2000 2005 2008 2010 2011 2017 + 16 110 344 350 1274 1280 1284 1287 1451 1457 1476 1481 1668 1672 2014 2016 2018 + +1 +BND_defaultFaces +3 + 671 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 + +