From fb71dff8bc35d3e9cc15bc96a0474421fb291523 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Wed, 3 Mar 2021 23:29:03 +0100 Subject: [PATCH 01/42] mesh refactoring: moved points from StorageLayerFamily to Mesh, replaced template argument EntityTopology of SubentityStorageLayerFamily and SuperentityStorageLayerFamily by DimensionTag --- src/TNL/Meshes/Mesh.h | 11 +++- src/TNL/Meshes/Mesh.hpp | 33 +++++++++- .../Meshes/MeshDetails/layers/StorageLayer.h | 64 ++++++------------- .../layers/SubentityStorageLayer.h | 53 +++++++-------- .../layers/SuperentityStorageLayer.h | 50 +++++++-------- 5 files changed, 111 insertions(+), 100 deletions(-) diff --git a/src/TNL/Meshes/Mesh.h b/src/TNL/Meshes/Mesh.h index 506850ece..01a9d3408 100644 --- a/src/TNL/Meshes/Mesh.h +++ b/src/TNL/Meshes/Mesh.h @@ -126,6 +126,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 +141,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,9 +275,7 @@ 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 >; diff --git a/src/TNL/Meshes/Mesh.hpp b/src/TNL/Meshes/Mesh.hpp index b7394ea2c..582980511 100644 --- a/src/TNL/Meshes/Mesh.hpp +++ b/src/TNL/Meshes/Mesh.hpp @@ -45,6 +45,7 @@ Mesh( const Mesh& mesh ) : StorageBaseType( mesh ), EntityTagsLayerFamily( mesh ) { + points = mesh.getPoints(); } template< typename MeshConfig, typename Device > @@ -54,6 +55,7 @@ Mesh( const Mesh< MeshConfig, Device_ >& mesh ) : StorageBaseType( mesh ), EntityTagsLayerFamily( mesh ) { + points = mesh.getPoints(); } template< typename MeshConfig, typename Device > @@ -61,6 +63,7 @@ Mesh< MeshConfig, Device >& Mesh< MeshConfig, Device >:: operator=( const Mesh& mesh ) { + points = mesh.getPoints(); StorageBaseType::operator=( mesh ); EntityTagsLayerFamily::operator=( mesh ); return *this; @@ -72,6 +75,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 +110,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 +142,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__ @@ -330,6 +359,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 +369,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/MeshDetails/layers/StorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h index 38bddd657..4bed80ecf 100644 --- a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h @@ -48,9 +48,6 @@ 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; @@ -67,7 +64,6 @@ public: StorageLayerFamily& operator=( const StorageLayerFamily& layer ) { - points = layer.getPoints(); BaseType::operator=( layer ); DualGraphLayer< MeshConfig, Device >::operator=( layer ); return *this; @@ -76,7 +72,6 @@ public: template< typename Device_ > StorageLayerFamily& operator=( const StorageLayerFamily< MeshConfig, Device_ >& layer ) { - points = layer.getPoints(); BaseType::operator=( layer ); DualGraphLayer< MeshConfig, Device >::operator=( layer ); return *this; @@ -84,35 +79,10 @@ 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 ) - { - BaseType::setEntitiesCount( DimensionTag< Dimension >(), entitiesCount ); - if( Dimension == 0 ) - points.setSize( entitiesCount ); - } - template< int Dimension, int Subdimension > __cuda_callable__ typename MeshTraitsType::LocalIndexType @@ -122,8 +92,8 @@ public: 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 >; + Device, + DimensionTag< Dimension > >; return BaseType::template getSubentitiesCount< Subdimension >(); } @@ -136,8 +106,8 @@ public: 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, + DimensionTag< Dimension > >; return BaseType::template getSubentitiesMatrix< Subdimension >(); } @@ -150,8 +120,8 @@ public: 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, + DimensionTag< Dimension > >; return BaseType::template getSubentitiesMatrix< Subdimension >(); } @@ -165,7 +135,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 +149,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 +163,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 +177,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 >(); } }; @@ -222,10 +192,13 @@ class StorageLayer< MeshConfig, true > : public SubentityStorageLayerFamily< MeshConfig, Device, - typename MeshTraits< MeshConfig, Device >::template EntityTraits< DimensionTag::value >::EntityTopology >, + DimensionTag >, + public SubentityOrientationsLayerFamily< MeshConfig, + Device, + 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: @@ -235,8 +208,9 @@ public: using EntityTraitsType = typename MeshTraitsType::template EntityTraits< DimensionTag::value >; using EntityType = typename EntityTraitsType::EntityType; using EntityTopology = typename EntityTraitsType::EntityTopology; - using SubentityStorageBaseType = SubentityStorageLayerFamily< MeshConfig, Device, EntityTopology >; - using SuperentityStorageBaseType = SuperentityStorageLayerFamily< MeshConfig, Device, EntityTopology >; + using SubentityStorageBaseType = SubentityStorageLayerFamily< MeshConfig, Device, DimensionTag >; + using SubentityOrientationsBaseType = SubentityOrientationsLayerFamily< MeshConfig, Device, EntityTopology >; + using SuperentityStorageBaseType = SuperentityStorageLayerFamily< MeshConfig, Device, DimensionTag >; StorageLayer() = default; diff --git a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h index 5aa1ee579..f9f890cbd 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -26,18 +26,18 @@ namespace Meshes { template< typename MeshConfig, typename Device, - typename EntityTopology, + typename EntityTopologyDimensionTag, typename SubdimensionTag, - bool SubentityStorage = WeakSubentityStorageTrait< MeshConfig, Device, EntityTopology, SubdimensionTag >::storageEnabled > + bool SubentityStorage = WeakSubentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopologyDimensionTag::value >::EntityTopology, SubdimensionTag >::storageEnabled > class SubentityStorageLayer; template< typename MeshConfig, typename Device, - typename EntityTopology > + typename EntityTopologyDimensionTag > class SubentityStorageLayerFamily - : public SubentityStorageLayer< MeshConfig, Device, EntityTopology, DimensionTag< 0 > > + : public SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, DimensionTag< 0 > > { - using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, DimensionTag< 0 > >; + using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, DimensionTag< 0 > >; using MeshTraitsType = MeshTraits< MeshConfig, Device >; public: @@ -51,7 +51,7 @@ protected: typename MeshTraitsType::LocalIndexType getSubentitiesCount() const { - static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); + static_assert( EntityTopologyDimensionTag::value > Subdimension, "Invalid combination of Dimension and Subdimension." ); return BaseType::getSubentitiesCount( DimensionTag< Subdimension >() ); } @@ -60,7 +60,7 @@ protected: typename MeshTraitsType::SubentityMatrixType& getSubentitiesMatrix() { - static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); + static_assert( EntityTopologyDimensionTag::value > Subdimension, "Invalid combination of Dimension and Subdimension." ); return BaseType::getSubentitiesMatrix( DimensionTag< Subdimension >() ); } @@ -69,23 +69,23 @@ protected: const typename MeshTraitsType::SubentityMatrixType& getSubentitiesMatrix() const { - static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); + static_assert( EntityTopologyDimensionTag::value > Subdimension, "Invalid combination of Dimension and Subdimension." ); return BaseType::getSubentitiesMatrix( DimensionTag< Subdimension >() ); } }; template< typename MeshConfig, typename Device, - typename EntityTopology, + typename EntityTopologyDimensionTag, typename SubdimensionTag > class SubentityStorageLayer< MeshConfig, Device, - EntityTopology, + EntityTopologyDimensionTag, SubdimensionTag, true > - : public SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment > + : public SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SubdimensionTag::Increment > { - using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment >; + using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SubdimensionTag::Increment >; using MeshTraitsType = MeshTraits< MeshConfig, Device >; protected: @@ -101,7 +101,7 @@ protected: } template< typename Device_ > - SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SubdimensionTag >& other ) { operator=( other ); } @@ -114,7 +114,7 @@ protected: } template< typename Device_ > - SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) + SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SubdimensionTag >& other ) { BaseType::operator=( other ); matrix = other.matrix; @@ -125,7 +125,7 @@ protected: 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 << "Adjacency matrix for subentities with dimension " << SubdimensionTag::value << " of entities with dimension " << EntityTopologyDimensionTag::value << " is: " << std::endl; str << matrix << std::endl; } @@ -140,6 +140,7 @@ protected: __cuda_callable__ LocalIndexType getSubentitiesCount( SubdimensionTag ) const { + using EntityTopology = typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopologyDimensionTag::value >::EntityTopology; using SubentityTraitsType = typename MeshTraitsType::template SubentityTraits< EntityTopology, SubdimensionTag::value >; return SubentityTraitsType::count; } @@ -161,22 +162,22 @@ private: 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 EntityTopologyDimensionTag_, typename SubdimensionTag_, bool Storage_ > friend class SubentityStorageLayer; }; template< typename MeshConfig, typename Device, - typename EntityTopology, + typename EntityTopologyDimensionTag, typename SubdimensionTag > class SubentityStorageLayer< MeshConfig, Device, - EntityTopology, + EntityTopologyDimensionTag, SubdimensionTag, false > - : public SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment > + : public SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SubdimensionTag::Increment > { - using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment >; + using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SubdimensionTag::Increment >; public: // inherit constructors and assignment operators (including templated versions) using BaseType::BaseType; @@ -186,14 +187,14 @@ public: // termination of recursive inheritance (everything is reduced to EntityStorage == false thanks to the WeakSubentityStorageTrait) template< typename MeshConfig, typename Device, - typename EntityTopology > + typename EntityTopologyDimensionTag > class SubentityStorageLayer< MeshConfig, Device, - EntityTopology, - DimensionTag< EntityTopology::dimension >, + EntityTopologyDimensionTag, + DimensionTag< EntityTopologyDimensionTag::value >, false > { - using SubdimensionTag = DimensionTag< EntityTopology::dimension >; + using SubdimensionTag = EntityTopologyDimensionTag; protected: using GlobalIndexType = typename MeshConfig::GlobalIndexType; @@ -201,9 +202,9 @@ protected: SubentityStorageLayer() = default; explicit SubentityStorageLayer( const SubentityStorageLayer& other ) {} template< typename Device_ > - SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) {} + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SubdimensionTag >& other ) {} template< typename Device_ > - SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { return *this; } + SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SubdimensionTag >& other ) { return *this; } void print( std::ostream& str ) const {} diff --git a/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h index 3cd6a5a29..a26353156 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 EntityTopologyDimensionTag, typename SuperdimensionTag, - bool SuperentityStorage = WeakSuperentityStorageTrait< MeshConfig, Device, EntityTopology, SuperdimensionTag >::storageEnabled > + bool SuperentityStorage = WeakSuperentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopologyDimensionTag::value >::EntityTopology, SuperdimensionTag >::storageEnabled > class SuperentityStorageLayer; template< typename MeshConfig, typename Device, - typename EntityTopology > + typename EntityTopologyDimensionTag > class SuperentityStorageLayerFamily : public SuperentityStorageLayer< MeshConfig, Device, - EntityTopology, + EntityTopologyDimensionTag, DimensionTag< MeshTraits< MeshConfig, Device >::meshDimension > > { using BaseType = SuperentityStorageLayer< MeshConfig, Device, - EntityTopology, + EntityTopologyDimensionTag, 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( EntityTopologyDimensionTag::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( EntityTopologyDimensionTag::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( EntityTopologyDimensionTag::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( EntityTopologyDimensionTag::value < Superdimension, "Invalid combination of Dimension and Superdimension." ); return BaseType::getSuperentitiesMatrix( DimensionTag< Superdimension >() ); } }; template< typename MeshConfig, typename Device, - typename EntityTopology, + typename EntityTopologyDimensionTag, typename SuperdimensionTag > -class SuperentityStorageLayer< MeshConfig, Device, EntityTopology, SuperdimensionTag, true > - : public SuperentityStorageLayer< MeshConfig, Device, EntityTopology, typename SuperdimensionTag::Decrement > +class SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, SuperdimensionTag, true > + : public SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SuperdimensionTag::Decrement > { - using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityTopology, typename SuperdimensionTag::Decrement >; + using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SuperdimensionTag::Decrement >; using MeshTraitsType = MeshTraits< MeshConfig, Device >; protected: @@ -111,7 +111,7 @@ protected: } template< typename Device_ > - SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopology, SuperdimensionTag >& other ) + SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SuperdimensionTag >& other ) { operator=( other ); } @@ -125,7 +125,7 @@ protected: } template< typename Device_ > - SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopology, SuperdimensionTag >& other ) + SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SuperdimensionTag >& other ) { BaseType::operator=( other ); superentitiesCounts = other.superentitiesCounts; @@ -137,7 +137,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 " << EntityTopologyDimensionTag::value << " is: " << std::endl; str << matrix << std::endl; } @@ -186,12 +186,12 @@ private: template< typename MeshConfig, typename Device, - typename EntityTopology, + typename EntityTopologyDimensionTag, typename SuperdimensionTag > -class SuperentityStorageLayer< MeshConfig, Device, EntityTopology, SuperdimensionTag, false > - : public SuperentityStorageLayer< MeshConfig, Device, EntityTopology, typename SuperdimensionTag::Decrement > +class SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, SuperdimensionTag, false > + : public SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SuperdimensionTag::Decrement > { - using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityTopology, typename SuperdimensionTag::Decrement >; + using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SuperdimensionTag::Decrement >; public: // inherit constructors and assignment operators (including templated versions) using BaseType::BaseType; @@ -201,18 +201,18 @@ 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 EntityTopologyDimensionTag > +class SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, EntityTopologyDimensionTag, false > { - using SuperdimensionTag = DimensionTag< EntityTopology::dimension >; + using SuperdimensionTag = EntityTopologyDimensionTag; protected: SuperentityStorageLayer() = default; explicit SuperentityStorageLayer( const SuperentityStorageLayer& other ) {} template< typename Device_ > - SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopology, SuperdimensionTag >& other ) {} + SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SuperdimensionTag >& other ) {} template< typename Device_ > - SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopology, SuperdimensionTag >& other ) { return *this; } + SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SuperdimensionTag >& other ) { return *this; } void getSuperentitiesCountsArray() {} -- GitLab From 40aa3f830786696ca59fe3908339d84b670e81f7 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Mon, 22 Mar 2021 22:21:10 +0100 Subject: [PATCH 02/42] Added Polygon mesh topology - added Polygon to Topologies - added mapping of Topologies::Polygon to EntityShape::Polygon in VTKTraits - added a missing reference to a variable in MeshBuilder::validate --- src/TNL/Meshes/MeshBuilder.h | 2 +- src/TNL/Meshes/Topologies/Polygon.h | 28 ++++++++++++++++++++++++++++ src/TNL/Meshes/VTKTraits.h | 12 +++++++----- 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 src/TNL/Meshes/Topologies/Polygon.h diff --git a/src/TNL/Meshes/MeshBuilder.h b/src/TNL/Meshes/MeshBuilder.h index 8dc390633..86e6a9f02 100644 --- a/src/TNL/Meshes/MeshBuilder.h +++ b/src/TNL/Meshes/MeshBuilder.h @@ -92,7 +92,7 @@ private: assignedPoints.setValue( false ); for( GlobalIndexType i = 0; i < getCellsCount(); i++ ) { - const auto cornerIds = this->cellSeeds[ i ].getCornerIds(); + 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 ] ) { diff --git a/src/TNL/Meshes/Topologies/Polygon.h b/src/TNL/Meshes/Topologies/Polygon.h new file mode 100644 index 000000000..558f5a0ec --- /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/VTKTraits.h b/src/TNL/Meshes/VTKTraits.h index 143654f71..6b367862b 100644 --- a/src/TNL/Meshes/VTKTraits.h +++ b/src/TNL/Meshes/VTKTraits.h @@ -19,6 +19,7 @@ #include #include #include +#include namespace TNL { namespace Meshes { @@ -122,12 +123,13 @@ 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::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::Tetrahedron > { static constexpr EntityShape shape = EntityShape::Tetra; }; +template<> struct TopologyToEntityShape< Topologies::Hexahedron > { static constexpr EntityShape shape = EntityShape::Hexahedron; }; +template<> struct TopologyToEntityShape< Topologies::Polygon > { static constexpr EntityShape shape = EntityShape::Polygon; }; // mapping used in VTKWriter template< typename GridEntity > -- GitLab From bdbd12c44b69825fa512ff14453f3049647d4b9f Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Thu, 25 Mar 2021 17:33:15 +0100 Subject: [PATCH 03/42] Extension of Mesh for Polygons - added SubentityMatrixType to MeshSubentityTraits and modified SubentityMatrixType in MeshTraits to get SubentityMatrixType from MeshSubentityTraits based on Dimension and Subdimension template arguments - refactored template argument EntityTopologyDimensionTag of SubentityStorageLayer back to EntityTopology to allow specializing for Polygon - added Polygon specialization for MeshSubentityTraits that uses different SubentityMatrixType and leaves out any count related defined types - added Polygon specialization for SubentityStorageLayer, that unlike SubentityStorageLayer used in other cell topologies, additionaly stores subentiesCounts - added setSubentitiesCounts function to mesh and its storage related parent classes for setting subentitiesCounts in SubentityStorageLayer - modified getSubentitiesCount function in mesh to pass the unused entityIndex parameter to StorageBaseType::getSubentitiesCount to enable retrieving variable subentitiesCounts from Polygon specialization of SubentityStorageLayer --- src/TNL/Meshes/Mesh.h | 3 + src/TNL/Meshes/Mesh.hpp | 10 +- .../Meshes/MeshDetails/layers/StorageLayer.h | 32 ++- .../layers/SubentityStorageLayer.h | 231 +++++++++++++++--- .../MeshDetails/traits/MeshSubentityTraits.h | 27 ++ .../Meshes/MeshDetails/traits/MeshTraits.h | 3 +- 6 files changed, 262 insertions(+), 44 deletions(-) diff --git a/src/TNL/Meshes/Mesh.h b/src/TNL/Meshes/Mesh.h index 01a9d3408..1e4f53110 100644 --- a/src/TNL/Meshes/Mesh.h +++ b/src/TNL/Meshes/Mesh.h @@ -281,6 +281,9 @@ class Mesh 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 582980511..baeed61a1 100644 --- a/src/TNL/Meshes/Mesh.hpp +++ b/src/TNL/Meshes/Mesh.hpp @@ -180,6 +180,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 > @@ -188,7 +196,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 > diff --git a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h index 4bed80ecf..a53c3bb34 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 >; @@ -83,23 +84,36 @@ public: DualGraphLayer< MeshConfig, Device >::operator==( layer ) ); } + template< int Dimension, int Subdimension > + void + setSubentitiesCounts( const typename MeshTraitsType::NeighborCountsArray& counts ) + { + static_assert( Dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); + static_assert( SubentityTraits< Dimension, Subdimension >::storageEnabled, + "You try to set subentitiesCounts for subentities which are 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, - DimensionTag< Dimension > >; - return BaseType::template getSubentitiesCount< Subdimension >(); + 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, Subdimension >& getSubentitiesMatrix() { static_assert( Dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); @@ -107,13 +121,13 @@ public: "You try to get subentities matrix which is disabled in the mesh configuration." ); using BaseType = SubentityStorageLayerFamily< MeshConfig, Device, - DimensionTag< Dimension > >; + 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, Subdimension >& getSubentitiesMatrix() const { static_assert( Dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); @@ -121,7 +135,7 @@ public: "You try to get subentities matrix which is disabled in the mesh configuration." ); using BaseType = SubentityStorageLayerFamily< MeshConfig, Device, - DimensionTag< Dimension > >; + typename EntityTraits< Dimension >::EntityTopology >; return BaseType::template getSubentitiesMatrix< Subdimension >(); } @@ -192,7 +206,7 @@ class StorageLayer< MeshConfig, true > : public SubentityStorageLayerFamily< MeshConfig, Device, - DimensionTag >, + typename MeshTraits< MeshConfig, Device >::template EntityTraits< DimensionTag::value >::EntityTopology >, public SubentityOrientationsLayerFamily< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< DimensionTag::value >::EntityTopology >, @@ -208,7 +222,7 @@ public: using EntityTraitsType = typename MeshTraitsType::template EntityTraits< DimensionTag::value >; using EntityType = typename EntityTraitsType::EntityType; using EntityTopology = typename EntityTraitsType::EntityTopology; - using SubentityStorageBaseType = SubentityStorageLayerFamily< MeshConfig, Device, DimensionTag >; + using SubentityStorageBaseType = SubentityStorageLayerFamily< MeshConfig, Device, EntityTopology >; using SubentityOrientationsBaseType = SubentityOrientationsLayerFamily< MeshConfig, Device, EntityTopology >; using SuperentityStorageBaseType = SuperentityStorageLayerFamily< MeshConfig, Device, DimensionTag >; diff --git a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h index f9f890cbd..e7f5a5c15 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -20,25 +20,27 @@ #include #include #include +#include namespace TNL { namespace Meshes { template< typename MeshConfig, typename Device, - typename EntityTopologyDimensionTag, + typename EntityTopology, typename SubdimensionTag, - bool SubentityStorage = WeakSubentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopologyDimensionTag::value >::EntityTopology, SubdimensionTag >::storageEnabled > + bool SubentityStorage = WeakSubentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopology::dimension >::EntityTopology, SubdimensionTag >::storageEnabled > class SubentityStorageLayer; template< typename MeshConfig, typename Device, - typename EntityTopologyDimensionTag > + typename EntityTopology > class SubentityStorageLayerFamily - : public SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, DimensionTag< 0 > > + : public SubentityStorageLayer< MeshConfig, Device, EntityTopology, DimensionTag< 0 > > { - using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, DimensionTag< 0 > >; + 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,52 +48,60 @@ 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 > __cuda_callable__ typename MeshTraitsType::LocalIndexType - getSubentitiesCount() const + getSubentitiesCount( const GlobalIndexType entityIndex ) const { - static_assert( EntityTopologyDimensionTag::value > Subdimension, "Invalid combination of Dimension and Subdimension." ); - return BaseType::getSubentitiesCount( DimensionTag< Subdimension >() ); + static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); + return BaseType::getSubentitiesCount( DimensionTag< Subdimension >( ), entityIndex ); } template< int Subdimension > __cuda_callable__ - typename MeshTraitsType::SubentityMatrixType& + typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, Subdimension >& getSubentitiesMatrix() { - static_assert( EntityTopologyDimensionTag::value > Subdimension, "Invalid combination of Dimension and Subdimension." ); + static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); return BaseType::getSubentitiesMatrix( DimensionTag< Subdimension >() ); } template< int Subdimension > __cuda_callable__ - const typename MeshTraitsType::SubentityMatrixType& + const typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, Subdimension >& getSubentitiesMatrix() const { - static_assert( EntityTopologyDimensionTag::value > Subdimension, "Invalid combination of Dimension and Subdimension." ); + static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); return BaseType::getSubentitiesMatrix( DimensionTag< Subdimension >() ); } }; template< typename MeshConfig, typename Device, - typename EntityTopologyDimensionTag, + typename EntityTopology, typename SubdimensionTag > class SubentityStorageLayer< MeshConfig, Device, - EntityTopologyDimensionTag, + EntityTopology, SubdimensionTag, true > - : public SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SubdimensionTag::Increment > + : public SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment > { - using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, 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 SubentityMatrixType = typename MeshTraitsType::SubentityMatrixType; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, SubdimensionTag::value >; SubentityStorageLayer() = default; @@ -101,7 +111,7 @@ protected: } template< typename Device_ > - SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SubdimensionTag >& other ) + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { operator=( other ); } @@ -114,7 +124,7 @@ protected: } template< typename Device_ > - SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SubdimensionTag >& other ) + SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { BaseType::operator=( other ); matrix = other.matrix; @@ -125,7 +135,7 @@ protected: void print( std::ostream& str ) const { BaseType::print( str ); - str << "Adjacency matrix for subentities with dimension " << SubdimensionTag::value << " of entities with dimension " << EntityTopologyDimensionTag::value << " is: " << std::endl; + str << "Adjacency matrix for subentities with dimension " << SubdimensionTag::value << " of entities with dimension " << EntityTopology::dimension << " is: " << std::endl; str << matrix << std::endl; } @@ -136,11 +146,14 @@ protected: } protected: + using BaseType::setSubentitiesCounts; + void setSubentitiesCounts( SubdimensionTag, const typename MeshTraitsType::NeighborCountsArray& counts ) + {} + using BaseType::getSubentitiesCount; __cuda_callable__ - LocalIndexType getSubentitiesCount( SubdimensionTag ) const + LocalIndexType getSubentitiesCount( SubdimensionTag, const GlobalIndexType entityIndex ) const { - using EntityTopology = typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopologyDimensionTag::value >::EntityTopology; using SubentityTraitsType = typename MeshTraitsType::template SubentityTraits< EntityTopology, SubdimensionTag::value >; return SubentityTraitsType::count; } @@ -162,22 +175,135 @@ private: SubentityMatrixType matrix; // friend class is needed for templated assignment operators - template< typename MeshConfig_, typename Device_, typename EntityTopologyDimensionTag_, typename SubdimensionTag_, bool Storage_ > + template< typename MeshConfig_, typename Device_, typename EntityTopology_, typename SubdimensionTag_, bool Storage_ > friend class SubentityStorageLayer; }; template< typename MeshConfig, typename Device, - typename EntityTopologyDimensionTag, typename SubdimensionTag > class SubentityStorageLayer< MeshConfig, Device, - EntityTopologyDimensionTag, + Topologies::Polygon, + SubdimensionTag, + true > + : public SubentityStorageLayer< MeshConfig, Device, Topologies::Polygon, typename SubdimensionTag::Increment > +{ + using EntityTopology = Topologies::Polygon; + 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, SubdimensionTag::value >; + + SubentityStorageLayer() = default; + + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) + { + operator=( other ); + } + + template< typename Device_ > + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) + { + operator=( other ); + } + + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) + { + BaseType::operator=( other ); + subentitiesCounts = other.subentitiesCounts; + matrix = other.matrix; + return *this; + } + + 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; + } + + 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_ > + friend class SubentityStorageLayer; +}; + +template< typename MeshConfig, + typename Device, + typename EntityTopology, + typename SubdimensionTag > +class SubentityStorageLayer< MeshConfig, + Device, + EntityTopology, SubdimensionTag, false > - : public SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SubdimensionTag::Increment > + : public SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment > { - using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SubdimensionTag::Increment >; + using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment >; public: // inherit constructors and assignment operators (including templated versions) using BaseType::BaseType; @@ -187,14 +313,52 @@ public: // termination of recursive inheritance (everything is reduced to EntityStorage == false thanks to the WeakSubentityStorageTrait) template< typename MeshConfig, typename Device, - typename EntityTopologyDimensionTag > + typename EntityTopology > class SubentityStorageLayer< MeshConfig, Device, - EntityTopologyDimensionTag, - DimensionTag< EntityTopologyDimensionTag::value >, + EntityTopology, + DimensionTag< EntityTopology::dimension >, false > { - using SubdimensionTag = EntityTopologyDimensionTag; + using MeshTraitsType = MeshTraits< MeshConfig, Device >; + using SubdimensionTag = DimensionTag< EntityTopology::dimension >; + +protected: + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + + SubentityStorageLayer() = default; + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) {} + template< typename Device_ > + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) {} + template< typename Device_ > + SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { return *this; } + + void print( std::ostream& str ) const {} + + bool operator==( const SubentityStorageLayer& layer ) const + { + return true; + } + + void save( File& file ) const {} + void load( File& file ) {} + + void setSubentitiesCounts( SubdimensionTag, const typename MeshTraitsType::NeighborCountsArray& ); + void getSubentitiesCount( SubdimensionTag ) {} + void getSubentitiesMatrix( SubdimensionTag ) {} +}; + +template< typename MeshConfig, + typename Device > +class SubentityStorageLayer< MeshConfig, + Device, + Topologies::Polygon, + DimensionTag< Topologies::Polygon::dimension >, + false > +{ + using MeshTraitsType = MeshTraits< MeshConfig, Device >; + using EntityTopology = Topologies::Polygon; + using SubdimensionTag = DimensionTag< EntityTopology::dimension >; protected: using GlobalIndexType = typename MeshConfig::GlobalIndexType; @@ -202,9 +366,9 @@ protected: SubentityStorageLayer() = default; explicit SubentityStorageLayer( const SubentityStorageLayer& other ) {} template< typename Device_ > - SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SubdimensionTag >& other ) {} + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) {} template< typename Device_ > - SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SubdimensionTag >& other ) { return *this; } + SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { return *this; } void print( std::ostream& str ) const {} @@ -213,6 +377,7 @@ protected: return true; } + void setSubentitiesCounts( SubdimensionTag, const typename MeshTraitsType::NeighborCountsArray& ); void getSubentitiesCount( SubdimensionTag ) {} void getSubentitiesMatrix( SubdimensionTag ) {} }; diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h index 830db3f2b..d9d43940e 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h @@ -19,6 +19,7 @@ #include #include #include +#include namespace TNL { namespace Meshes { @@ -42,6 +43,9 @@ public: using SubentityTopology = typename MeshEntityTraits< MeshConfig, Device, Dimension >::EntityTopology; using SubentityType = typename MeshEntityTraits< MeshConfig, Device, Dimension >::EntityType; + // container for storing the subentity indices + using SubentityMatrixType = Matrices::SparseMatrix< bool, Device, GlobalIndexType, Matrices::GeneralMatrix, EllpackSegments >; + template< LocalIndexType subentityIndex, LocalIndexType subentityVertexIndex > struct Vertex @@ -54,5 +58,28 @@ public: }; }; +// Specialization for Polygons +template< typename MeshConfig, + typename Device, + int Dimension > +class MeshSubentityTraits +{ + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + using EntityTopology = Topologies::Polygon; + +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; + + // container for storing the subentity indices + using SubentityMatrixType = Matrices::SparseMatrix< bool, Device, GlobalIndexType, Matrices::GeneralMatrix, SlicedEllpackSegments >; +}; + } // namespace Meshes } // namespace TNL diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h index 3f8c5f444..2b14337a4 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h @@ -75,7 +75,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, int Subdimension > + using SubentityMatrixType = typename SubentityTraits< typename EntityTraits< Dimension >::EntityTopology, Subdimension >::SubentityMatrixType; // container for storing the superentity indices using SuperentityMatrixType = Matrices::SparseMatrix< bool, Device, GlobalIndexType, Matrices::GeneralMatrix, SlicedEllpackSegments >; -- GitLab From b37161a82336cfaed8ff7e0a6436642020cade1e Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Thu, 25 Mar 2021 17:37:02 +0100 Subject: [PATCH 04/42] Generalization of Mesh Initialization to handle Polygons - added Polygon specialization for EntitySeed and EntitySeedHash that uses Array instead of StaticArray to handle variable number of cornerIds - refactored template argument EntityDimensionTag of SubentitySeedsCreator to EntityTopology to allow specializing for Polygons - added Polygon specialization for SubentitySeedsCreator to handle variable amounts of vertices per polygon - added getSubentitiesCount function to SubentitySeedsCreator to retrieve number of subentities to be created from passed in vertices - modified Initializer::initSubentityMatrix function to retrieve capacities from a method argument instead of creating them statically from traits and to pass in retrieved capacities to Mesh::setSubentitiesCounts - removed EntityInitializer::initSubvertexMatrix function and replaced all calls to it with Initializer::initSubentityMatrix - modified EntityInitializerLayer::initSuperentities and InitializerLayer::initEntities functions to calculate subentity matrix capacities before a call to Initializer::initSubentityMatrix --- .../initializer/EntityInitializer.h | 36 ++++-- .../MeshDetails/initializer/EntitySeed.h | 68 +++++++++++ .../MeshDetails/initializer/Initializer.h | 35 ++++-- .../initializer/SubentitySeedsCreator.h | 111 ++++++++++++++++-- 4 files changed, 218 insertions(+), 32 deletions(-) diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h index d7bab6523..ecfee77b7 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h @@ -56,11 +56,6 @@ class EntityInitializer using InitializerType = Initializer< MeshConfig >; public: - static void initSubvertexMatrix( const GlobalIndexType entitiesCount, InitializerType& initializer ) - { - initializer.template initSubentityMatrix< EntityTopology::dimension, 0 >( entitiesCount ); - } - static void initEntity( const GlobalIndexType entityIndex, const SeedType& entitySeed, InitializerType& initializer ) { // this is necessary if we want to use existing entities instead of intermediate seeds to create subentity seeds @@ -82,7 +77,6 @@ class EntityInitializer< MeshConfig, EntityTopology, false > using SeedType = EntitySeed< MeshConfig, EntityTopology >; using InitializerType = Initializer< MeshConfig >; public: - static void initSubvertexMatrix( const GlobalIndexType entitiesCount, InitializerType& initializer ) {} static void initEntity( const GlobalIndexType entityIndex, const SeedType& entitySeed, InitializerType& initializer ) {} }; @@ -111,6 +105,7 @@ class EntityInitializerLayer< MeshConfig, typename SuperdimensionTag::Decrement >; using InitializerType = Initializer< MeshConfig >; using MeshType = typename InitializerType::MeshType; + using MeshTraitsType = typename MeshType::MeshTraitsType; using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; @@ -118,8 +113,9 @@ class EntityInitializerLayer< MeshConfig, 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 SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperentityTopology, SubdimensionTag >; using SuperentityMatrixType = typename MeshTraits< MeshConfig >::SuperentityMatrixType; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: static void initSuperentities( InitializerType& meshInitializer, MeshType& mesh ) @@ -128,8 +124,16 @@ 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 ); + { + NeighborCountsArray capacities( superentitiesCount ); + + for( GlobalIndexType superentityIndex = 0; superentityIndex < capacities.getSize(); superentityIndex++ ) + capacities[ superentityIndex ] = SubentitySeedsCreatorType::getSubentitiesCount( meshInitializer.template getSubvertices< SuperdimensionTag::value >( 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 >(); @@ -138,6 +142,7 @@ public: for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { + //TODO: try to pass capacitites in to avoid calculating number of non-zero elements in a row auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) { @@ -194,12 +199,14 @@ class EntityInitializerLayer< MeshConfig, typename SuperdimensionTag::Decrement >; using InitializerType = Initializer< MeshConfig >; using MeshType = typename InitializerType::MeshType; + using MeshTraitsType = typename MeshType::MeshTraitsType; 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 SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperentityTopology, SubdimensionTag >; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: static void initSuperentities( InitializerType& meshInitializer, MeshType& mesh ) @@ -209,8 +216,15 @@ 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 ); + { + NeighborCountsArray capacities( superentitiesCount ); + for( GlobalIndexType superentityIndex = 0; superentityIndex < capacities.getSize(); superentityIndex++ ) + capacities[ superentityIndex ] = SubentitySeedsCreatorType::getSubentitiesCount( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); + + meshInitializer.template initSubentityMatrix< SuperdimensionTag::value, SubdimensionTag::value >( capacities, subentitiesCount ); + } + for( GlobalIndexType superentityIndex = 0; superentityIndex < mesh.template getEntitiesCount< SuperdimensionTag::value >(); superentityIndex++ ) @@ -259,7 +273,7 @@ class EntityInitializerLayer< MeshConfig, 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 SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperentityTopology, SubdimensionTag >; using SuperentityMatrixType = typename MeshTraits< MeshConfig >::SuperentityMatrixType; public: diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h index 41439c405..7320bfe48 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h @@ -17,6 +17,7 @@ #pragma once #include +#include namespace TNL { namespace Meshes { @@ -107,6 +108,53 @@ class EntitySeed< MeshConfig, Topologies::Vertex > IdArrayType cornerIds; }; +template< typename MeshConfig > +class EntitySeed< MeshConfig, Topologies::Polygon > +{ + using MeshConfigTraits = MeshTraits< MeshConfig >; + +public: + using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; + using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; + using DeviceType = typename MeshTraits< MeshConfig >::DeviceType; + using IdArrayType = Containers::Array< GlobalIndexType, DeviceType, LocalIndexType >; + using HashType = EntitySeedHash< EntitySeed >; + using KeyEqual = EntitySeedEq< EntitySeed >; + + void setCornersCount( const LocalIndexType& cornersCount ) + { + TNL_ASSERT_GE( cornersCount, 3, "cornersCount must be at least 3" ); + 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 ) { @@ -132,6 +180,26 @@ struct EntitySeedHash } }; +template< typename MeshConfig > +struct EntitySeedHash< EntitySeed< MeshConfig, Topologies::Polygon > > +{ + using Seed = EntitySeed< MeshConfig, Topologies::Polygon >; + + std::size_t operator()( const Seed& seed ) const + { + using LocalIndexType = typename Seed::LocalIndexType; + using GlobalIndexType = typename Seed::GlobalIndexType; + + // 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 < seed.getCornersCount(); i++ ) +// hash ^= std::hash< GlobalIndexType >{}( seed.getCornerIds()[ i ] ); + hash += std::hash< GlobalIndexType >{}( seed.getCornerIds()[ i ] ); + return hash; + } +}; + template< typename EntitySeed > struct EntitySeedEq { diff --git a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index f8d5775ca..67c38c916 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -80,7 +80,10 @@ class Initializer using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; 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, Subdimension >::RowsCapacitiesType; // The points and cellSeeds arrays will be reset when not needed to save memory. void createMesh( PointArrayType& points, @@ -97,19 +100,14 @@ class Initializer } template< int Dimension, int Subdimension > - void initSubentityMatrix( const GlobalIndexType entitiesCount, GlobalIndexType subentitiesCount = 0 ) + void initSubentityMatrix( const 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 ); + mesh->template setSubentitiesCounts< Dimension, Subdimension >( capacities ); } template< int Dimension > @@ -171,6 +169,7 @@ class InitializerLayer< MeshConfig, typename MeshTraits< MeshConfig >::Dimension using InitializerType = Initializer< MeshConfig >; using EntityInitializerType = EntityInitializer< MeshConfig, EntityTopology >; using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: @@ -178,7 +177,14 @@ class InitializerLayer< MeshConfig, typename MeshTraits< MeshConfig >::Dimension { //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() ); + + NeighborCountsArray capacities( cellSeeds.getSize() ); + + for( LocalIndexType i = 0; i < capacities.getSize(); i++ ) + capacities[ i ] = cellSeeds[ i ].getCornersCount(); + + initializer.template initSubentityMatrix< EntityTopology::dimension, 0 >( capacities ); + for( GlobalIndexType i = 0; i < cellSeeds.getSize(); i++ ) EntityInitializerType::initEntity( i, cellSeeds[ i ], initializer ); cellSeeds.reset(); @@ -212,12 +218,13 @@ class InitializerLayer 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 NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: GlobalIndexType getEntitiesCount( InitializerType& initializer, MeshType& mesh ) { - using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, Meshes::DimensionTag< MeshType::getMeshDimension() >, DimensionTag >; + using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, typename MeshTraitsType::CellTopology, DimensionTag >; SeedSet seedSet; for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) @@ -241,9 +248,13 @@ class InitializerLayer //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; const GlobalIndexType numberOfEntities = getEntitiesCount( initializer, mesh ); initializer.template setEntitiesCount< DimensionTag::value >( numberOfEntities ); - EntityInitializerType::initSubvertexMatrix( numberOfEntities, initializer ); - using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, Meshes::DimensionTag< MeshType::getMeshDimension() >, DimensionTag >; + NeighborCountsArray capacities( numberOfEntities ); + int vertexCount = MeshTraitsType::template SubentityTraits< EntityTopology, 0 >::count; + capacities.setValue( vertexCount ); + initializer.template initSubentityMatrix< EntityTopology::dimension, 0 >( capacities ); + + using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, typename MeshTraitsType::CellTopology, DimensionTag >; for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) { auto subentitySeeds = SubentitySeedsCreator::create( initializer.template getSubvertices< MeshType::getMeshDimension() >( i ) ); diff --git a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h index 52dcc73c7..edc7b0d2c 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h +++ b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h @@ -18,20 +18,20 @@ #include #include +#include namespace TNL { namespace Meshes { template< typename MeshConfig, - typename EntityDimensionTag, + typename EntityTopology, typename SubentityDimensionTag > class SubentitySeedsCreator { using MeshTraitsType = MeshTraits< MeshConfig >; 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 SubvertexAccessorType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, SubentityDimensionTag::value >::RowView; using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, SubentityDimensionTag::value >; using SubentityTopology = typename SubentityTraits::SubentityTopology; @@ -57,17 +57,66 @@ public: return subentitySeeds; } + + static LocalIndexType getSubentitiesCount( const SubvertexAccessorType& subvertices ) + { + return SubentityTraits::count; + } +}; + +template< typename MeshConfig > +class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 1 > > +{ + using MeshTraitsType = MeshTraits< MeshConfig >; + using DeviceType = typename MeshTraitsType::DeviceType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using EntityTopology = Topologies::Polygon; + using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; + using SubvertexAccessorType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, 1 >::RowView; + using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 1 >; + using SubentityTopology = typename SubentityTraits::SubentityTopology; + +public: + using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; + using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; + + static SubentitySeedArray create( const SubvertexAccessorType& subvertices ) + { + SubentitySeedArray seeds; + LocalIndexType verticesCount = getVerticesCount( subvertices ); + seeds.setSize( verticesCount ); + + for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) + { + SubentitySeed& seed = seeds[ i ]; + seed.setCornerId( 0, subvertices.getColumnIndex( i ) ); + seed.setCornerId( 1, subvertices.getColumnIndex( (i + 1) % verticesCount ) ); + } + + return seeds; + } + + static LocalIndexType getSubentitiesCount( const SubvertexAccessorType& subvertices ) + { + return getVerticesCount( subvertices ); + } +private: + static LocalIndexType getVerticesCount( const SubvertexAccessorType& subvertices ) + { + LocalIndexType i; + for( i = 0; i < subvertices.getSize() && subvertices.getColumnIndex( i ) >= 0; i++ ) {} + return i; + } }; template< typename MeshConfig, - typename EntityDimensionTag > -class SubentitySeedsCreator< MeshConfig, EntityDimensionTag, DimensionTag< 0 > > + typename EntityTopology > +class SubentitySeedsCreator< MeshConfig, EntityTopology, DimensionTag< 0 > > { using MeshTraitsType = MeshTraits< MeshConfig >; 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 SubvertexAccessorType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, 0 >::RowView; using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 0 >; using SubentityTopology = typename SubentityTraits::SubentityTopology; @@ -81,6 +130,50 @@ public: seeds[ i ].setCornerId( 0, subvertices.getColumnIndex( i ) ); return seeds; } + + static LocalIndexType getSubentitiesCount( const SubvertexAccessorType& subvertices ) + { + return subvertices.getSize(); + } +}; + +template< typename MeshConfig > +class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 0 > > +{ + using MeshTraitsType = MeshTraits< MeshConfig >; + using DeviceType = typename MeshTraitsType::DeviceType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using EntityTopology = Topologies::Polygon; + using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; + using SubvertexAccessorType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, 0 >::RowView; + using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 0 >; + using SubentityTopology = typename SubentityTraits::SubentityTopology; + +public: + using SubentitySeedArray = Containers::Array< EntitySeed< MeshConfig, SubentityTopology >, DeviceType, LocalIndexType >; + + static SubentitySeedArray create( const SubvertexAccessorType& subvertices ) + { + SubentitySeedArray seeds; + seeds.setSize( getVerticesCount( subvertices ) ); + + for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) + seeds[ i ].setCornerId( 0, subvertices.getColumnIndex( i ) ); + + return seeds; + } + + static LocalIndexType getSubentitiesCount( const SubvertexAccessorType& subvertices ) + { + return getVerticesCount( subvertices ); + } +private: + static LocalIndexType getVerticesCount( const SubvertexAccessorType& subvertices ) + { + LocalIndexType i; + for( i = 0; i < subvertices.getSize() && subvertices.getColumnIndex( i ) >= 0; i++ ) {} + return i; + } }; } // namespace Meshes -- GitLab From 2eb885b15d903a3cc56fd5cc5bf6708f684ec093 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Thu, 25 Mar 2021 17:38:53 +0100 Subject: [PATCH 05/42] Added simple unit test for Mesh with two Polygons --- src/UnitTests/Meshes/MeshTest.h | 199 ++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/src/UnitTests/Meshes/MeshTest.h b/src/UnitTests/Meshes/MeshTest.h index 9125e04e8..8098b89a8 100644 --- a/src/UnitTests/Meshes/MeshTest.h +++ b/src/UnitTests/Meshes/MeshTest.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "EntityTests.h" @@ -55,6 +56,13 @@ public: static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } }; +class TestPolygonMeshConfig : 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; } +}; + template< typename Object1, typename Object2 > void compareStringRepresentation( const Object1& obj1, const Object2& obj2 ) { @@ -968,6 +976,197 @@ TEST( MeshTest, RegularMeshOfHexahedronsTest ) testFinishedMesh( mesh ); } +TEST( MeshTest, PolygonTest ) +{ + using PolygonMeshEntityType = MeshEntity< TestPolygonMeshConfig, 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 | + | (rectangle) | + 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 ); + + typedef Mesh< TestPolygonMeshConfig > PolygonTestMesh; + PolygonTestMesh mesh; + MeshBuilder< PolygonTestMesh > meshBuilder; + + meshBuilder.setPointsCount( 5 ); + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + + meshBuilder.setCellsCount( 2 ); + + meshBuilder.getCellSeed( 0 ).setCornersCount( 4 ); + EXPECT_EQ( meshBuilder.getCellSeed( 0 ).getCornersCount(), 4 ); + + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); + EXPECT_EQ( meshBuilder.getCellSeed( 0 ).getCornerIds() [ 0 ], 0 ); + EXPECT_EQ( meshBuilder.getCellSeed( 0 ).getCornerIds() [ 1 ], 1 ); + EXPECT_EQ( meshBuilder.getCellSeed( 0 ).getCornerIds() [ 2 ], 2 ); + EXPECT_EQ( meshBuilder.getCellSeed( 0 ).getCornerIds() [ 3 ], 3 ); + + meshBuilder.getCellSeed( 1 ).setCornersCount( 3 ); + EXPECT_EQ( meshBuilder.getCellSeed( 1 ).getCornersCount(), 3 ); + + meshBuilder.getCellSeed( 1 ).setCornerId( 0, 3 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 1, 2 ); + meshBuilder.getCellSeed( 1 ).setCornerId( 2, 4 ); + EXPECT_EQ( meshBuilder.getCellSeed( 1 ).getCornerIds() [ 0 ], 3 ); + EXPECT_EQ( meshBuilder.getCellSeed( 1 ).getCornerIds() [ 1 ], 2 ); + EXPECT_EQ( meshBuilder.getCellSeed( 1 ).getCornerIds() [ 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 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< 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 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 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 ); +}; + } // namespace MeshTest #endif -- GitLab From c25535d2d41b6a95ae90808a04e67d72094ec34d Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Thu, 25 Mar 2021 18:16:39 +0100 Subject: [PATCH 06/42] Mesh: Refactoring and fix for wrong declaration --- .../MeshDetails/initializer/EntitySeed.h | 20 ------------------- .../Meshes/MeshDetails/layers/StorageLayer.h | 2 -- .../layers/SubentityStorageLayer.h | 2 +- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h index 7320bfe48..5970be03a 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h @@ -170,26 +170,6 @@ struct EntitySeedHash using LocalIndexType = typename EntitySeed::LocalIndexType; using GlobalIndexType = typename EntitySeed::GlobalIndexType; - // 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++ ) -// hash ^= std::hash< GlobalIndexType >{}( seed.getCornerIds()[ i ] ); - hash += std::hash< GlobalIndexType >{}( seed.getCornerIds()[ i ] ); - return hash; - } -}; - -template< typename MeshConfig > -struct EntitySeedHash< EntitySeed< MeshConfig, Topologies::Polygon > > -{ - using Seed = EntitySeed< MeshConfig, Topologies::Polygon >; - - std::size_t operator()( const Seed& seed ) const - { - using LocalIndexType = typename Seed::LocalIndexType; - using GlobalIndexType = typename Seed::GlobalIndexType; - // 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; diff --git a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h index a53c3bb34..b112ee53d 100644 --- a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h @@ -89,8 +89,6 @@ public: setSubentitiesCounts( const typename MeshTraitsType::NeighborCountsArray& counts ) { static_assert( Dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); - static_assert( SubentityTraits< Dimension, Subdimension >::storageEnabled, - "You try to set subentitiesCounts for subentities which are disabled in the mesh configuration." ); using BaseType = SubentityStorageLayerFamily< MeshConfig, Device, typename EntityTraits< Dimension >::EntityTopology >; diff --git a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h index e7f5a5c15..b8ec66cde 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -343,7 +343,7 @@ protected: void save( File& file ) const {} void load( File& file ) {} - void setSubentitiesCounts( SubdimensionTag, const typename MeshTraitsType::NeighborCountsArray& ); + void setSubentitiesCounts( SubdimensionTag, const typename MeshTraitsType::NeighborCountsArray& ) {} void getSubentitiesCount( SubdimensionTag ) {} void getSubentitiesMatrix( SubdimensionTag ) {} }; -- GitLab From 3dbfb472ed5aab37f81ba5e8662fea515bde66f2 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Fri, 26 Mar 2021 20:42:25 +0100 Subject: [PATCH 07/42] Fixed failed static assertions in mesh initializer --- .../Meshes/MeshDetails/initializer/EntityInitializer.h | 8 ++++++++ src/TNL/Meshes/MeshDetails/initializer/Initializer.h | 4 ++-- src/TNL/Meshes/MeshDetails/layers/StorageLayer.h | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h index ecfee77b7..e210b820c 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h @@ -54,8 +54,14 @@ class EntityInitializer using SeedType = EntitySeed< MeshConfig, EntityTopology >; using InitializerType = Initializer< MeshConfig >; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: + static void initSubvertexMatrix( const NeighborCountsArray& capacities, InitializerType& initializer ) + { + initializer.template initSubentityMatrix< EntityTopology::dimension, 0 >( capacities ); + } + static void initEntity( const GlobalIndexType entityIndex, const SeedType& entitySeed, InitializerType& initializer ) { // this is necessary if we want to use existing entities instead of intermediate seeds to create subentity seeds @@ -76,7 +82,9 @@ class EntityInitializer< MeshConfig, EntityTopology, false > using SeedType = EntitySeed< MeshConfig, EntityTopology >; using InitializerType = Initializer< MeshConfig >; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: + static void initSubvertexMatrix( const NeighborCountsArray& capacities, InitializerType& initializer ) {} static void initEntity( const GlobalIndexType entityIndex, const SeedType& entitySeed, InitializerType& initializer ) {} }; diff --git a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index 67c38c916..c438e9e1d 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -183,7 +183,7 @@ class InitializerLayer< MeshConfig, typename MeshTraits< MeshConfig >::Dimension for( LocalIndexType i = 0; i < capacities.getSize(); i++ ) capacities[ i ] = cellSeeds[ i ].getCornersCount(); - initializer.template initSubentityMatrix< EntityTopology::dimension, 0 >( capacities ); + EntityInitializerType::initSubvertexMatrix( capacities, initializer ); for( GlobalIndexType i = 0; i < cellSeeds.getSize(); i++ ) EntityInitializerType::initEntity( i, cellSeeds[ i ], initializer ); @@ -252,7 +252,7 @@ class InitializerLayer NeighborCountsArray capacities( numberOfEntities ); int vertexCount = MeshTraitsType::template SubentityTraits< EntityTopology, 0 >::count; capacities.setValue( vertexCount ); - initializer.template initSubentityMatrix< EntityTopology::dimension, 0 >( capacities ); + EntityInitializerType::initSubvertexMatrix( capacities, initializer ); using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, typename MeshTraitsType::CellTopology, DimensionTag >; for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) diff --git a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h index b112ee53d..387f2e9c4 100644 --- a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h @@ -89,6 +89,8 @@ public: setSubentitiesCounts( const typename MeshTraitsType::NeighborCountsArray& counts ) { 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 >; -- GitLab From 1c33ec48b3830da62b915c5d36ea06f1fc2ac56c Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Wed, 31 Mar 2021 15:57:10 +0200 Subject: [PATCH 08/42] Added unit test for mesh with seven polygons --- src/UnitTests/Meshes/MeshTest.h | 493 +++++++++++++++++++++++++++++++- 1 file changed, 489 insertions(+), 4 deletions(-) diff --git a/src/UnitTests/Meshes/MeshTest.h b/src/UnitTests/Meshes/MeshTest.h index 8098b89a8..63245e86a 100644 --- a/src/UnitTests/Meshes/MeshTest.h +++ b/src/UnitTests/Meshes/MeshTest.h @@ -56,13 +56,22 @@ public: static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } }; -class TestPolygonMeshConfig : public DefaultConfig< Topologies::Polygon > +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; } +}; + +//struct TestMeshConfigTag {}; + template< typename Object1, typename Object2 > void compareStringRepresentation( const Object1& obj1, const Object2& obj2 ) { @@ -976,9 +985,10 @@ TEST( MeshTest, RegularMeshOfHexahedronsTest ) testFinishedMesh( mesh ); } -TEST( MeshTest, PolygonTest ) +TEST( MeshTest, TwoPolygonsTest ) { - using PolygonMeshEntityType = MeshEntity< TestPolygonMeshConfig, Devices::Host, Topologies::Polygon >; + 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; @@ -1024,7 +1034,6 @@ TEST( MeshTest, PolygonTest ) point3( 1.0, 0.5 ), point4( 0.5, 1.0 ); - typedef Mesh< TestPolygonMeshConfig > PolygonTestMesh; PolygonTestMesh mesh; MeshBuilder< PolygonTestMesh > meshBuilder; @@ -1087,18 +1096,22 @@ TEST( MeshTest, PolygonTest ) 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 ); @@ -1167,6 +1180,478 @@ TEST( MeshTest, PolygonTest ) 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.setPointsCount( 16 ); + 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.setCellsCount( 7 ); + + // 1 0 3 2 4 5 + meshBuilder.getCellSeed( 0 ).setCornersCount( 6 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ); +}; + } // namespace MeshTest #endif -- GitLab From f61ec71a3f0a3069a8c3a1372ef5904a9750e5d7 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Wed, 31 Mar 2021 15:58:08 +0200 Subject: [PATCH 09/42] Modified MeshReader to handle reading Polygonal meshes --- src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h | 6 ++++++ src/TNL/Meshes/Readers/MeshReader.h | 1 + src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp | 2 ++ src/TNL/Meshes/Writers/VTKWriter.hpp | 8 ++++++++ src/TNL/Meshes/Writers/VTUWriter.hpp | 2 ++ src/Tools/tnl-mesh-converter.cpp | 1 + 6 files changed, 20 insertions(+) diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h index 5970be03a..74af00889 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h @@ -41,6 +41,9 @@ class EntitySeed 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; @@ -81,6 +84,9 @@ class EntitySeed< MeshConfig, Topologies::Vertex > 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; diff --git a/src/TNL/Meshes/Readers/MeshReader.h b/src/TNL/Meshes/Readers/MeshReader.h index 6d7398c28..5595fac62 100644 --- a/src/TNL/Meshes/Readers/MeshReader.h +++ b/src/TNL/Meshes/Readers/MeshReader.h @@ -199,6 +199,7 @@ public: for( std::size_t i = 0; i < NumberOfCells; i++ ) { CellSeedType& seed = meshBuilder.getCellSeed( i ); const std::size_t offsetEnd = offsets[ i ]; + seed.setCornersCount( offsetEnd - offsetStart ); for( std::size_t o = offsetStart; o < offsetEnd; o++ ) seed.setCornerId( o - offsetStart, connectivity[ o ] ); offsetStart = offsetEnd; diff --git a/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp b/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp index 72d3c8ef7..58383c300 100644 --- a/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp +++ b/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp @@ -51,6 +51,8 @@ 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) ); default: std::cerr << "unsupported cell topology: " << VTK::getShapeName( reader.getCellShape() ) << std::endl; return false; diff --git a/src/TNL/Meshes/Writers/VTKWriter.hpp b/src/TNL/Meshes/Writers/VTKWriter.hpp index 87b795081..0a5b44f0b 100644 --- a/src/TNL/Meshes/Writers/VTKWriter.hpp +++ b/src/TNL/Meshes/Writers/VTKWriter.hpp @@ -65,6 +65,8 @@ struct MeshEntitiesVTKWriter const int verticesPerEntity = VerticesPerEntity< EntityType >::count;; for( Index i = 0; i < entitiesCount; i++ ) { const auto& entity = mesh.template getEntity< EntityType >( i ); + //TODO: polygons require verticesPerEntity to be aquired like below + //const Index verticesPerEntity = entity.template getSubentitiesCount< 0 >(); writeInt( format, str, verticesPerEntity ); for( int j = 0; j < verticesPerEntity; j++ ) writeInt( format, str, entity.template getSubentityIndex< 0 >( j ) ); @@ -445,6 +447,12 @@ VTKWriter< Mesh >::writeEntities( const Mesh& mesh ) const int verticesPerEntity = VerticesPerEntity< EntityType >::count; const std::uint64_t cellsListSize = cellsCount * ( verticesPerEntity + 1 ); + //TODO: polygons need cellsListSize computed like this, but code doesnt compile, + // because function writeEntities is also used for grids, that don't contain function getSubentitiesCount + /*IndexType cellsListSize = cellsCount; + for(IndexType index = 0; index < cellsCount; index++) + cellsListSize += mesh.template getSubentitiesCount< EntityDimension, 0 >( index );*/ + 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 e26b2942a..295357bca 100644 --- a/src/TNL/Meshes/Writers/VTUWriter.hpp +++ b/src/TNL/Meshes/Writers/VTUWriter.hpp @@ -46,6 +46,8 @@ struct MeshEntitiesVTUCollector const Index verticesPerEntity = VerticesPerEntity< EntityType >::count;; for( Index i = 0; i < entitiesCount; i++ ) { const auto& entity = mesh.template getEntity< EntityType >( i ); + //TODO: polygons require verticesPerEntity to be aquired like below + //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/Tools/tnl-mesh-converter.cpp b/src/Tools/tnl-mesh-converter.cpp index bbaf82175..e125c66e3 100644 --- a/src/Tools/tnl-mesh-converter.cpp +++ b/src/Tools/tnl-mesh-converter.cpp @@ -43,6 +43,7 @@ template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Trian template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Quadrangle > { 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::Polygon > { enum { enabled = true }; }; // Meshes are enabled only for the space dimension equal to the cell dimension. template< typename CellTopology, int SpaceDimension > -- GitLab From b1affc050d645b2df7b658c53520c93ae8c318b5 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Mon, 5 Apr 2021 23:11:47 +0200 Subject: [PATCH 10/42] Extended functionality of Mesh reader and writer - modified VTKReader and VTUReader to handle reading meshes with mixed cell shapes, that can be generalized to polygons - modified VTKWriter and VTUWriter to handle writing Polygonal meshes --- src/TNL/Meshes/EntityShapeGroup.h | 39 ++++++++++++++++++ src/TNL/Meshes/EntityShapeGroupChecker.h | 49 +++++++++++++++++++++++ src/TNL/Meshes/Readers/VTKReader.h | 36 ++++++++++++++--- src/TNL/Meshes/Readers/VTUReader.h | 27 +++++++++++-- src/TNL/Meshes/VTKTraits.h | 2 +- src/TNL/Meshes/Writers/EntitiesListSize.h | 45 +++++++++++++++++++++ src/TNL/Meshes/Writers/VTKWriter.hpp | 14 ++----- src/TNL/Meshes/Writers/VTUWriter.hpp | 4 +- src/Tools/tnl-mesh-converter.cpp | 2 +- 9 files changed, 194 insertions(+), 24 deletions(-) create mode 100644 src/TNL/Meshes/EntityShapeGroup.h create mode 100644 src/TNL/Meshes/EntityShapeGroupChecker.h create mode 100644 src/TNL/Meshes/Writers/EntitiesListSize.h diff --git a/src/TNL/Meshes/EntityShapeGroup.h b/src/TNL/Meshes/EntityShapeGroup.h new file mode 100644 index 000000000..f9938068d --- /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 000000000..619d9a539 --- /dev/null +++ b/src/TNL/Meshes/EntityShapeGroupChecker.h @@ -0,0 +1,49 @@ +#pragma once + +#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::TemplateStaticFor< int, 0, EntityShapeGroup< GeneralShape >::size, OtherEntitiesChecker >::execHost( result, shape ); + return result; + } + } + + static bool bothBelong( EntityShape shape1, EntityShape shape2 ) + { + return belong( shape1 ) && belong( shape2 ); + } + +private: + template< int index > + class OtherEntitiesChecker + { + public: + static void exec( bool& result, EntityShape shape ) + { + EntityShape groupShape = EntityShapeGroupElement< GeneralShape, index >::shape; + result = result || ( shape == groupShape ); + } + }; +}; + +} // namespace VTK +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Readers/VTKReader.h b/src/TNL/Meshes/Readers/VTKReader.h index a4a1c943e..aeb69300d 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,33 @@ public: } // validate cell types + using PolygonShapeGroupChecker = VTK::EntityShapeGroupChecker< VTK::EntityShape::Polygon >; + //TODO: uncomment line below later for polyhedrals + //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 ); + { + if( (VTK::EntityShape) c != 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 +198,12 @@ 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 ]; + + 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++ ) { diff --git a/src/TNL/Meshes/Readers/VTUReader.h b/src/TNL/Meshes/Readers/VTUReader.h index bae1c3381..222deb955 100644 --- a/src/TNL/Meshes/Readers/VTUReader.h +++ b/src/TNL/Meshes/Readers/VTUReader.h @@ -94,11 +94,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 ); diff --git a/src/TNL/Meshes/VTKTraits.h b/src/TNL/Meshes/VTKTraits.h index 6b367862b..7c71f5024 100644 --- a/src/TNL/Meshes/VTKTraits.h +++ b/src/TNL/Meshes/VTKTraits.h @@ -126,10 +126,10 @@ 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::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::Polygon > { static constexpr EntityShape shape = EntityShape::Polygon; }; // 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 000000000..15e13d9d9 --- /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/VTKWriter.hpp b/src/TNL/Meshes/Writers/VTKWriter.hpp index 0a5b44f0b..ada849aef 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,11 +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 ); - //TODO: polygons require verticesPerEntity to be aquired like below - //const Index verticesPerEntity = entity.template getSubentitiesCount< 0 >(); + 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 ) ); @@ -444,14 +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 ); - - //TODO: polygons need cellsListSize computed like this, but code doesnt compile, - // because function writeEntities is also used for grids, that don't contain function getSubentitiesCount - /*IndexType cellsListSize = cellsCount; - for(IndexType index = 0; index < cellsCount; index++) - cellsListSize += mesh.template getSubentitiesCount< EntityDimension, 0 >( index );*/ + 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 295357bca..385537a52 100644 --- a/src/TNL/Meshes/Writers/VTUWriter.hpp +++ b/src/TNL/Meshes/Writers/VTUWriter.hpp @@ -43,11 +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 ); - //TODO: polygons require verticesPerEntity to be aquired like below - //const Index verticesPerEntity = entity.template getSubentitiesCount< 0 >(); + 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/Tools/tnl-mesh-converter.cpp b/src/Tools/tnl-mesh-converter.cpp index e125c66e3..30e19b508 100644 --- a/src/Tools/tnl-mesh-converter.cpp +++ b/src/Tools/tnl-mesh-converter.cpp @@ -43,7 +43,7 @@ template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Trian template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Quadrangle > { 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::Polygon > { enum { enabled = true }; }; +template<> struct MeshCellTopologyTag< MeshConverterConfigTag, Topologies::Polygon > { enum { enabled = true }; }; // Meshes are enabled only for the space dimension equal to the cell dimension. template< typename CellTopology, int SpaceDimension > -- GitLab From cd968f701266740f662c65f2fbf61db918cafabf Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Mon, 5 Apr 2021 23:38:30 +0200 Subject: [PATCH 11/42] Added mising includes to fix compilation errors --- src/TNL/Meshes/EntityShapeGroupChecker.h | 1 + src/TNL/Meshes/Readers/VTUReader.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/TNL/Meshes/EntityShapeGroupChecker.h b/src/TNL/Meshes/EntityShapeGroupChecker.h index 619d9a539..dbf012359 100644 --- a/src/TNL/Meshes/EntityShapeGroupChecker.h +++ b/src/TNL/Meshes/EntityShapeGroupChecker.h @@ -1,5 +1,6 @@ #pragma once +#include #include namespace TNL { diff --git a/src/TNL/Meshes/Readers/VTUReader.h b/src/TNL/Meshes/Readers/VTUReader.h index 222deb955..c4ccaef5e 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 { -- GitLab From 3fbc7d83d26409037bf0302fc565b867d0062b5b Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Wed, 7 Apr 2021 13:18:36 +0200 Subject: [PATCH 12/42] New topologies for Mesh: Wedge and Pyramid - added wedge and pyramid topologies - modified mesh initialization related classes to handle wedge and pyramid topologies - added entries for wedge and pyramid into VTKTraits, MeshTypeResolver, tnl-mesh-converter - added unit tests for mesh with two wedges and mesh with two pyramids --- src/TNL/Meshes/EntityShapeGroupChecker.h | 23 +- src/TNL/Meshes/Mesh.h | 1 + src/TNL/Meshes/Mesh.hpp | 3 +- src/TNL/Meshes/MeshBuilder.h | 81 +- .../initializer/EntityInitializer.h | 49 +- .../MeshDetails/initializer/EntitySeed.h | 58 +- .../MeshDetails/initializer/Initializer.h | 109 +- .../initializer/SubentitySeedsCreator.h | 256 +- .../Meshes/MeshDetails/layers/StorageLayer.h | 4 - .../layers/SubentityStorageLayer.h | 68 +- .../layers/SuperentityStorageLayer.h | 50 +- .../MeshDetails/traits/MeshSubentityTraits.h | 7 +- .../Meshes/MeshDetails/traits/MeshTraits.h | 22 +- src/TNL/Meshes/Topologies/Polyhedron.h | 34 + src/TNL/Meshes/Topologies/Pyramid.h | 118 + .../Meshes/Topologies/SubentityVertexCount.h | 19 + src/TNL/Meshes/Topologies/Wedge.h | 123 + .../Meshes/TypeResolver/MeshTypeResolver.hpp | 4 + src/TNL/Meshes/VTKTraits.h | 24 +- src/Tools/tnl-mesh-converter.cpp | 4 +- src/UnitTests/Meshes/MeshTest.h | 2070 ++++++++++++++++- 21 files changed, 2914 insertions(+), 213 deletions(-) create mode 100644 src/TNL/Meshes/Topologies/Polyhedron.h create mode 100644 src/TNL/Meshes/Topologies/Pyramid.h create mode 100644 src/TNL/Meshes/Topologies/SubentityVertexCount.h create mode 100644 src/TNL/Meshes/Topologies/Wedge.h diff --git a/src/TNL/Meshes/EntityShapeGroupChecker.h b/src/TNL/Meshes/EntityShapeGroupChecker.h index dbf012359..35b0c5449 100644 --- a/src/TNL/Meshes/EntityShapeGroupChecker.h +++ b/src/TNL/Meshes/EntityShapeGroupChecker.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include namespace TNL { @@ -22,7 +22,14 @@ public: else { bool result = false; - Algorithms::TemplateStaticFor< int, 0, EntityShapeGroup< GeneralShape >::size, OtherEntitiesChecker >::execHost( result, shape ); + + Algorithms::staticFor< int, 0, EntityShapeGroup< GeneralShape >::size >( + [&] ( auto index ) { + EntityShape groupShape = EntityShapeGroupElement< GeneralShape, index >::shape; + result = result || ( shape == groupShape ); + } + ); + return result; } } @@ -31,18 +38,6 @@ public: { return belong( shape1 ) && belong( shape2 ); } - -private: - template< int index > - class OtherEntitiesChecker - { - public: - static void exec( bool& result, EntityShape shape ) - { - EntityShape groupShape = EntityShapeGroupElement< GeneralShape, index >::shape; - result = result || ( shape == groupShape ); - } - }; }; } // namespace VTK diff --git a/src/TNL/Meshes/Mesh.h b/src/TNL/Meshes/Mesh.h index 1e4f53110..c885cf512 100644 --- a/src/TNL/Meshes/Mesh.h +++ b/src/TNL/Meshes/Mesh.h @@ -50,6 +50,7 @@ class MeshInitializableBase // The points and cellSeeds arrays will be reset when not needed to save memory. void init( typename MeshTraitsType::PointArrayType& points, + typename MeshTraitsType::FaceSeedArrayType& faceSeeds, typename MeshTraitsType::CellSeedArrayType& cellSeeds ); }; diff --git a/src/TNL/Meshes/Mesh.hpp b/src/TNL/Meshes/Mesh.hpp index baeed61a1..5e2b72193 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::FaceSeedArrayType& faceSeeds, typename MeshTraitsType::CellSeedArrayType& 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 diff --git a/src/TNL/Meshes/MeshBuilder.h b/src/TNL/Meshes/MeshBuilder.h index 86e6a9f02..cb6fa23b6 100644 --- a/src/TNL/Meshes/MeshBuilder.h +++ b/src/TNL/Meshes/MeshBuilder.h @@ -32,6 +32,7 @@ public: using PointType = typename MeshTraitsType::PointType; using CellTopology = typename MeshTraitsType::CellTopology; using CellSeedType = typename MeshTraitsType::CellSeedType; + using FaceSeedType = typename MeshTraitsType::FaceSeedType; void setPointsCount( const GlobalIndexType& points ) { @@ -40,6 +41,11 @@ public: pointsSet.setValue( false ); } + void setFacesCount( const GlobalIndexType& facesCount ) + { + this->faceSeeds.setSize( facesCount ); + } + void setCellsCount( const GlobalIndexType& cellsCount ) { this->cellSeeds.setSize( cellsCount ); @@ -50,6 +56,11 @@ public: return this->points.getSize(); } + GlobalIndexType getFacesCount() const + { + return this->faceSeeds.getSize(); + } + GlobalIndexType getCellsCount() const { return this->cellSeeds.getSize(); @@ -62,6 +73,11 @@ public: this->pointsSet[ index ] = true; } + FaceSeedType& getFaceSeed( GlobalIndexType index ) + { + return this->faceSeeds[ index ]; + } + CellSeedType& getCellSeed( GlobalIndexType index ) { return this->cellSeeds[ index ]; @@ -71,13 +87,14 @@ public: { 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 FaceSeedArrayType = typename MeshTraitsType::FaceSeedArrayType; using BoolVector = Containers::Vector< bool, Devices::Host, GlobalIndexType >; bool validate() const @@ -91,26 +108,68 @@ 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& 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( 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& cornerIds = this->faceSeeds[ i ].getCornerIds(); + for( LocalIndexType j = 0; j < cornerIds.getSize(); j++ ) { + if( cornerIds[ j ] < 0 || getPointsCount() <= cornerIds[ j ] ) { + std::cerr << "face seed " << i << " is referencing unavailable point " << cornerIds[ j ] << std::endl; + return false; + } + assignedPoints[ cornerIds[ j ] ] = 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.setLike( faceSeeds ); + assignedFaces.setValue( false ); + + for( GlobalIndexType i = 0; i < getCellsCount(); i++ ) { + const auto& cornerIds = this->cellSeeds[ i ].getCornerIds(); + for( LocalIndexType j = 0; j < cornerIds.getSize(); j++ ) { + if( cornerIds[ j ] < 0 || getFacesCount() <= cornerIds[ j ] ) { + std::cerr << "cell seed " << i << " is referencing unavailable face " << cornerIds[ j ] << std::endl; + return false; + } + assignedFaces[ cornerIds[ j ] ] = 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; + FaceSeedArrayType faceSeeds; CellSeedArrayType cellSeeds; BoolVector pointsSet; }; diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h index e210b820c..5671ffd77 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h @@ -113,16 +113,16 @@ class EntityInitializerLayer< MeshConfig, typename SuperdimensionTag::Decrement >; using InitializerType = Initializer< MeshConfig >; using MeshType = typename InitializerType::MeshType; - using MeshTraitsType = typename MeshType::MeshTraitsType; + 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 SuperentityTopology = typename SuperentityTraitsType::EntityTopology; using SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperentityTopology, SubdimensionTag >; - using SuperentityMatrixType = typename MeshTraits< MeshConfig >::SuperentityMatrixType; + using SuperentityMatrixType = typename MeshTraitsType::SuperentityMatrixType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: @@ -133,12 +133,12 @@ public: const GlobalIndexType subentitiesCount = mesh.template getEntitiesCount< SubdimensionTag::value >(); const GlobalIndexType superentitiesCount = mesh.template getEntitiesCount< SuperdimensionTag::value >(); - if( SubdimensionTag::value > 0 ) + if( SubdimensionTag::value > 0 || std::is_same< SuperentityTopology, Topologies::Polyhedron >::value ) { NeighborCountsArray capacities( superentitiesCount ); for( GlobalIndexType superentityIndex = 0; superentityIndex < capacities.getSize(); superentityIndex++ ) - capacities[ superentityIndex ] = SubentitySeedsCreatorType::getSubentitiesCount( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); + capacities[ superentityIndex ] = SubentitySeedsCreatorType::getSubentitiesCount( meshInitializer, mesh, superentityIndex ); meshInitializer.template initSubentityMatrix< SuperdimensionTag::value, SubdimensionTag::value >( capacities, subentitiesCount ); } @@ -150,8 +150,7 @@ public: for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { - //TODO: try to pass capacitites in to avoid calculating number of non-zero elements in a row - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); + auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer, mesh, superentityIndex ); for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) { const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( subentitySeeds[ i ] ); @@ -207,11 +206,11 @@ class EntityInitializerLayer< MeshConfig, typename SuperdimensionTag::Decrement >; using InitializerType = Initializer< MeshConfig >; using MeshType = typename InitializerType::MeshType; - using MeshTraitsType = typename MeshType::MeshTraitsType; + 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 GlobalIndexType = typename MeshTraitsType::GlobalIndexType; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; + using SuperentityTraitsType = typename MeshTraitsType::template EntityTraits< SuperdimensionTag::value >; using SuperentityTopology = typename SuperentityTraitsType::EntityTopology; using SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperentityTopology, SubdimensionTag >; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; @@ -223,12 +222,12 @@ public: const GlobalIndexType subentitiesCount = mesh.template getEntitiesCount< SubdimensionTag::value >(); const GlobalIndexType superentitiesCount = mesh.template getEntitiesCount< SuperdimensionTag::value >(); - if( SubdimensionTag::value > 0 ) + if( SubdimensionTag::value > 0 || std::is_same< SuperentityTopology, Topologies::Polyhedron >::value ) { NeighborCountsArray capacities( superentitiesCount ); for( GlobalIndexType superentityIndex = 0; superentityIndex < capacities.getSize(); superentityIndex++ ) - capacities[ superentityIndex ] = SubentitySeedsCreatorType::getSubentitiesCount( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); + capacities[ superentityIndex ] = SubentitySeedsCreatorType::getSubentitiesCount( meshInitializer, mesh, superentityIndex ); meshInitializer.template initSubentityMatrix< SuperdimensionTag::value, SubdimensionTag::value >( capacities, subentitiesCount ); } @@ -237,8 +236,7 @@ public: superentityIndex < mesh.template getEntitiesCount< SuperdimensionTag::value >(); superentityIndex++ ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); - + auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer, mesh, superentityIndex ); for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) { const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( subentitySeeds[ i ] ); @@ -274,15 +272,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 SuperentityTraitsType = typename MeshTraitsType::template EntityTraits< SuperdimensionTag::value >; using SuperentityTopology = typename SuperentityTraitsType::EntityTopology; using SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperentityTopology, SubdimensionTag >; - using SuperentityMatrixType = typename MeshTraits< MeshConfig >::SuperentityMatrixType; + using SuperentityMatrixType = typename MeshTraitsType::SuperentityMatrixType; public: static void initSuperentities( InitializerType& meshInitializer, MeshType& mesh ) @@ -299,7 +298,7 @@ public: for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); + auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer, mesh, superentityIndex ); for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) { const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( subentitySeeds[ i ] ); @@ -316,7 +315,7 @@ public: // initialize superentities storage for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer.template getSubvertices< SuperdimensionTag::value >( superentityIndex ) ); + auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer, mesh, superentityIndex ); for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) { const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( subentitySeeds[ i ] ); diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h index 74af00889..6db4eed70 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h @@ -16,8 +16,10 @@ #pragma once +#include + #include -#include +#include namespace TNL { namespace Meshes { @@ -29,14 +31,14 @@ 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 >; @@ -73,13 +75,13 @@ 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 >; @@ -114,22 +116,34 @@ class EntitySeed< MeshConfig, Topologies::Vertex > IdArrayType cornerIds; }; -template< typename MeshConfig > -class EntitySeed< MeshConfig, Topologies::Polygon > +template< typename MeshConfig, + typename EntityTopology > +class EntitySeed< MeshConfig, EntityTopology, true > { - using MeshConfigTraits = MeshTraits< MeshConfig >; + using MeshTraitsType = MeshTraits< MeshConfig >; public: - using GlobalIndexType = typename MeshTraits< MeshConfig >::GlobalIndexType; - using LocalIndexType = typename MeshTraits< MeshConfig >::LocalIndexType; - using DeviceType = typename MeshTraits< MeshConfig >::DeviceType; - using IdArrayType = Containers::Array< GlobalIndexType, DeviceType, LocalIndexType >; + 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 ) { - TNL_ASSERT_GE( cornersCount, 3, "cornersCount must be at least 3" ); + 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 ); } @@ -195,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/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index c438e9e1d..5f6134c83 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -70,7 +70,7 @@ 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 >; @@ -78,6 +78,7 @@ class Initializer using BaseType = InitializerLayer< MeshConfig, DimensionTag >; using PointArrayType = typename MeshTraitsType::PointArrayType; using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; + using FaceSeedArrayType = typename MeshTraitsType::FaceSeedArrayType; using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; @@ -87,6 +88,7 @@ class Initializer // The points and cellSeeds arrays will be reset when not needed to save memory. void createMesh( PointArrayType& points, + FaceSeedArrayType& faceSeeds, CellSeedArrayType& cellSeeds, MeshType& mesh ) { @@ -96,7 +98,14 @@ 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 > @@ -131,6 +140,14 @@ 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 Superdimension > auto getSuperentitiesCountsArray() @@ -146,6 +163,13 @@ class Initializer { return mesh->template getSuperentitiesMatrix< Dimension, Superdimension >(); } + + CellSeedArrayType& getCellSeeds() + { + return *(this->cellSeeds); + } + protected: + CellSeedArrayType* cellSeeds = nullptr; }; /**** @@ -156,6 +180,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 >; @@ -169,6 +194,7 @@ class InitializerLayer< MeshConfig, typename MeshTraits< MeshConfig >::Dimension using InitializerType = Initializer< MeshConfig >; using EntityInitializerType = EntityInitializer< MeshConfig, EntityTopology >; using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; + using FaceSeedArrayType = typename MeshTraitsType::FaceSeedArrayType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: @@ -192,6 +218,13 @@ class InitializerLayer< MeshConfig, typename MeshTraits< MeshConfig >::Dimension BaseType::initEntities( initializer, mesh ); } + void initEntities( InitializerType& initializer, FaceSeedArrayType& faceSeeds, MeshType& mesh ) + { + //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; + initializer.template setEntitiesCount< DimensionTag::value >( initializer.getCellSeeds().getSize() ); + BaseType::initEntities( initializer, faceSeeds, mesh ); + } + using BaseType::findEntitySeedIndex; }; @@ -204,6 +237,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 >; @@ -218,6 +252,8 @@ class InitializerLayer 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 CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; + using EntitySeedArrayType = Containers::Array< SeedType, typename MeshTraitsType::DeviceType, GlobalIndexType >; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: @@ -229,7 +265,7 @@ class InitializerLayer for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) { - auto subentitySeeds = SubentitySeedsCreator::create( initializer.template getSubvertices< MeshType::getMeshDimension() >( i ) ); + auto subentitySeeds = SubentitySeedsCreator::create( initializer, mesh, i ); for( LocalIndexType j = 0; j < subentitySeeds.getSize(); j++ ) seedSet.insert( subentitySeeds[ j ] ); } @@ -237,6 +273,27 @@ class InitializerLayer return seedSet.size(); } + NeighborCountsArray getCapacities( InitializerType& initializer, MeshType& mesh, const GlobalIndexType numberOfEntities ) + { + using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, typename MeshTraitsType::CellTopology, DimensionTag >; + SeedSet seedSet; + NeighborCountsArray capacities( numberOfEntities ); + GlobalIndexType capSize = 0; + + for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) + { + auto subentitySeeds = SubentitySeedsCreator::create( initializer, mesh, i ); + for( LocalIndexType j = 0; j < subentitySeeds.getSize(); j++ ) + { + const auto& subentitySeed = subentitySeeds[ j ]; + bool inserted = seedSet.insert( subentitySeed ).second; + if( inserted ) + capacities.setElement( capSize++, subentitySeed.getCornersCount() ); + } + } + return capacities; + } + using BaseType::findEntitySeedIndex; GlobalIndexType findEntitySeedIndex( const SeedType& seed ) { @@ -248,16 +305,13 @@ class InitializerLayer //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; const GlobalIndexType numberOfEntities = getEntitiesCount( initializer, mesh ); initializer.template setEntitiesCount< DimensionTag::value >( numberOfEntities ); - - NeighborCountsArray capacities( numberOfEntities ); - int vertexCount = MeshTraitsType::template SubentityTraits< EntityTopology, 0 >::count; - capacities.setValue( vertexCount ); + NeighborCountsArray capacities = getCapacities( initializer, mesh, numberOfEntities ); EntityInitializerType::initSubvertexMatrix( capacities, initializer ); - + using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, typename MeshTraitsType::CellTopology, DimensionTag >; for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) { - auto subentitySeeds = SubentitySeedsCreator::create( initializer.template getSubvertices< MeshType::getMeshDimension() >( i ) ); + auto subentitySeeds = SubentitySeedsCreator::create( initializer, mesh, i ); for( LocalIndexType j = 0; j < subentitySeeds.getSize(); j++ ) { auto& seed = subentitySeeds[ j ]; @@ -276,6 +330,31 @@ class InitializerLayer BaseType::initEntities( initializer, mesh ); } + void initEntities( InitializerType& initializer, EntitySeedArrayType& faceSeeds, MeshType& mesh ) + { + //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; + initializer.template setEntitiesCount< DimensionTag::value >( faceSeeds.getSize() ); + + NeighborCountsArray capacities( faceSeeds.getSize() ); + + for( LocalIndexType i = 0; i < capacities.getSize(); i++ ) + capacities[ i ] = faceSeeds[ i ].getCornersCount(); + + EntityInitializerType::initSubvertexMatrix( capacities, initializer ); + + for( GlobalIndexType i = 0; i < faceSeeds.getSize(); i++ ) + { + const auto& seed = faceSeeds[ i ]; + GlobalIndexType entityIndex = this->seedsIndexedSet.insert( seed ); + EntityInitializerType::initEntity( entityIndex, seed, initializer ); + } + faceSeeds.reset(); + EntityInitializerType::initSuperentities( initializer, mesh ); + this->seedsIndexedSet.clear(); + initializer.getCellSeeds().reset(); + BaseType::initEntities( initializer, mesh ); + } + private: SeedIndexedSet seedsIndexedSet; }; @@ -287,17 +366,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 EntitySeedArrayType = Containers::Array< SeedType, typename MeshTraitsType::DeviceType, GlobalIndexType >; public: @@ -311,6 +391,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, EntitySeedArrayType& faceSeeds, MeshType& mesh ) + { + } }; } // namespace Meshes diff --git a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h index edc7b0d2c..3609211b4 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h +++ b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h @@ -19,6 +19,7 @@ #include #include #include +#include namespace TNL { namespace Meshes { @@ -28,28 +29,33 @@ template< typename MeshConfig, 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< EntityTopology::dimension >; - using SubvertexAccessorType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, SubentityDimensionTag::value >::RowView; 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 ) + 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 ) ); } ); } @@ -58,7 +64,7 @@ public: return subentitySeeds; } - static LocalIndexType getSubentitiesCount( const SubvertexAccessorType& subvertices ) + constexpr static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { return SubentityTraits::count; } @@ -67,12 +73,14 @@ public: 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 SubvertexAccessorType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, 1 >::RowView; using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 1 >; using SubentityTopology = typename SubentityTraits::SubentityTopology; @@ -80,32 +88,205 @@ public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; - 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 ); + const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); + SubentitySeedArray seeds; - LocalIndexType verticesCount = getVerticesCount( subvertices ); - seeds.setSize( verticesCount ); + seeds.setSize( subverticesCount ); for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) { SubentitySeed& seed = seeds[ i ]; seed.setCornerId( 0, subvertices.getColumnIndex( i ) ); - seed.setCornerId( 1, subvertices.getColumnIndex( (i + 1) % verticesCount ) ); + seed.setCornerId( 1, subvertices.getColumnIndex( (i + 1) % subverticesCount ) ); } return seeds; } - static LocalIndexType getSubentitiesCount( const SubvertexAccessorType& subvertices ) + static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { - return getVerticesCount( subvertices ); + 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 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, 2 >; + using SubentityTopology = typename SubentityTraits::SubentityTopology; + +public: + using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; + using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; + + static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + const auto& cellSeeds = initializer.getCellSeeds(); + const auto& faces = cellSeeds[ entityIndex ].getCornerIds(); + + SubentitySeedArray seeds; + seeds.setSize( faces.getSize() ); + + for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) + { + SubentitySeed& seed = seeds[ i ]; + GlobalIndexType faceIdx = faces[ i ]; + const auto& subvertices = mesh.template getSubentitiesMatrix< 2, 0 >().getRow( faceIdx ); + const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< 2, 0 >( faceIdx ); + seed.setCornersCount( subverticesCount ); + for( LocalIndexType j = 0; j < subverticesCount; j++ ) + { + seed.setCornerId( j, subvertices.getColumnIndex( j ) ); + } + } + + return seeds; } -private: - static LocalIndexType getVerticesCount( const SubvertexAccessorType& subvertices ) + + static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { - LocalIndexType i; - for( i = 0; i < subvertices.getSize() && subvertices.getColumnIndex( i ) >= 0; i++ ) {} - return i; + auto& cellSeeds = initializer.getCellSeeds(); + return cellSeeds[ entityIndex ].getCornersCount(); + } +}; + +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 >; + using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; + + static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + SubentitySeedArray seeds; + LocalIndexType subentitiesCount = getSubentitiesCount( initializer, mesh, entityIndex ); + seeds.setSize( subentitiesCount ); + GlobalIndexType seedsSize = 0; + + 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 ); + auto faceSubentitySeeds = FaceSubentitySeedsCreator::create( initializer, mesh, faceIdx ); + for( LocalIndexType j = 0; j < faceSubentitySeeds.getSize(); j++ ) + { + const auto& faceSubentitySeed = faceSubentitySeeds[ j ]; + bool inserted = seedSet.insert( faceSubentitySeed ).second; + if( inserted ) + seeds[ seedsSize++ ] = faceSubentitySeed; + } + } + + return seeds; + } + + 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 ); + auto faceSubentitySeeds = FaceSubentitySeedsCreator::create( initializer, mesh, faceIdx ); + for( LocalIndexType j = 0; j < faceSubentitySeeds.getSize(); j++ ) + seedSet.insert( faceSubentitySeeds[ j ] ); + } + + 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 >; + using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; + + static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + SubentitySeedArray seeds; + LocalIndexType subentitiesCount = getSubentitiesCount( initializer, mesh, entityIndex ); + seeds.setSize( subentitiesCount ); + GlobalIndexType seedsSize = 0; + + 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 ); + auto faceSubentitySeeds = FaceSubentitySeedsCreator::create( initializer, mesh, faceIdx ); + for( LocalIndexType j = 0; j < faceSubentitySeeds.getSize(); j++ ) + { + auto& faceSubentitySeed = faceSubentitySeeds[ j ]; + bool inserted = seedSet.insert( faceSubentitySeed ).second; + if( inserted ) + seeds[ seedsSize++ ] = faceSubentitySeed; + } + } + + return seeds; + } + + 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 ); + auto faceSubentitySeeds = FaceSubentitySeedsCreator::create( initializer, mesh, faceIdx ); + for( LocalIndexType j = 0; j < faceSubentitySeeds.getSize(); j++ ) + seedSet.insert( faceSubentitySeeds[ j ] ); + } + + return seedSet.size(); } }; @@ -113,49 +294,57 @@ template< typename MeshConfig, 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< EntityTopology::dimension >; - using SubvertexAccessorType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, 0 >::RowView; using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 0 >; using SubentityTopology = typename SubentityTraits::SubentityTopology; public: using SubentitySeedArray = Containers::StaticArray< SubentityTraits::count, EntitySeed< MeshConfig, SubentityTopology > >; - 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; } - static LocalIndexType getSubentitiesCount( const SubvertexAccessorType& subvertices ) + constexpr static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { - return subvertices.getSize(); + return SubentityTraits::count; } }; template< typename MeshConfig > class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 0 > > { + using MeshType = Mesh< MeshConfig >; using MeshTraitsType = MeshTraits< MeshConfig >; - using DeviceType = typename MeshTraitsType::DeviceType; + using InitializerType = Initializer< MeshConfig >; + using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; using EntityTopology = Topologies::Polygon; using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; - using SubvertexAccessorType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, 0 >::RowView; using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, 0 >; using SubentityTopology = typename SubentityTraits::SubentityTopology; public: - using SubentitySeedArray = Containers::Array< EntitySeed< MeshConfig, SubentityTopology >, DeviceType, LocalIndexType >; + using SubentitySeedArray = Containers::Array< EntitySeed< MeshConfig, SubentityTopology >, Devices::Host, LocalIndexType >; - 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 ); + const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); + SubentitySeedArray seeds; - seeds.setSize( getVerticesCount( subvertices ) ); + seeds.setSize( subverticesCount ); for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) seeds[ i ].setCornerId( 0, subvertices.getColumnIndex( i ) ); @@ -163,16 +352,9 @@ public: return seeds; } - static LocalIndexType getSubentitiesCount( const SubvertexAccessorType& subvertices ) - { - return getVerticesCount( subvertices ); - } -private: - static LocalIndexType getVerticesCount( const SubvertexAccessorType& subvertices ) + static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { - LocalIndexType i; - for( i = 0; i < subvertices.getSize() && subvertices.getColumnIndex( i ) >= 0; i++ ) {} - return i; + return mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); } }; diff --git a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h index 387f2e9c4..8423cc722 100644 --- a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h @@ -207,9 +207,6 @@ class StorageLayer< MeshConfig, : public SubentityStorageLayerFamily< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< DimensionTag::value >::EntityTopology >, - public SubentityOrientationsLayerFamily< MeshConfig, - Device, - typename MeshTraits< MeshConfig, Device >::template EntityTraits< DimensionTag::value >::EntityTopology >, public SuperentityStorageLayerFamily< MeshConfig, Device, DimensionTag >, @@ -223,7 +220,6 @@ public: using EntityType = typename EntityTraitsType::EntityType; using EntityTopology = typename EntityTraitsType::EntityTopology; using SubentityStorageBaseType = SubentityStorageLayerFamily< MeshConfig, Device, EntityTopology >; - using SubentityOrientationsBaseType = SubentityOrientationsLayerFamily< MeshConfig, Device, EntityTopology >; using SuperentityStorageBaseType = SuperentityStorageLayerFamily< MeshConfig, Device, DimensionTag >; StorageLayer() = default; diff --git a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h index b8ec66cde..ef09162c0 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace TNL { namespace Meshes { @@ -29,7 +30,9 @@ template< typename MeshConfig, typename Device, typename EntityTopology, typename SubdimensionTag, - bool SubentityStorage = WeakSubentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopology::dimension >::EntityTopology, SubdimensionTag >::storageEnabled > + bool SubentityStorage = WeakSubentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopology::dimension >::EntityTopology, SubdimensionTag >::storageEnabled, + bool dynamicTopology = std::is_same< EntityTopology, Topologies::Polygon >::value || + std::is_same< EntityTopology, Topologies::Polyhedron >::value > class SubentityStorageLayer; template< typename MeshConfig, @@ -92,7 +95,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 >; @@ -175,21 +179,22 @@ private: 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; }; template< typename MeshConfig, typename Device, + typename EntityTopology, typename SubdimensionTag > class SubentityStorageLayer< MeshConfig, Device, - Topologies::Polygon, + EntityTopology, SubdimensionTag, + true, true > - : public SubentityStorageLayer< MeshConfig, Device, Topologies::Polygon, typename SubdimensionTag::Increment > + : public SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment > { - using EntityTopology = Topologies::Polygon; using BaseType = SubentityStorageLayer< MeshConfig, Device, EntityTopology, typename SubdimensionTag::Increment >; using MeshTraitsType = MeshTraits< MeshConfig, Device >; @@ -288,19 +293,21 @@ private: 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; }; 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 >; @@ -313,51 +320,16 @@ 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 > -{ - using MeshTraitsType = MeshTraits< MeshConfig, Device >; - using SubdimensionTag = DimensionTag< EntityTopology::dimension >; - -protected: - using GlobalIndexType = typename MeshConfig::GlobalIndexType; - - SubentityStorageLayer() = default; - explicit SubentityStorageLayer( const SubentityStorageLayer& other ) {} - template< typename Device_ > - SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) {} - template< typename Device_ > - SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) { return *this; } - - void print( std::ostream& str ) const {} - - bool operator==( const SubentityStorageLayer& layer ) const - { - return true; - } - - void save( File& file ) const {} - void load( File& file ) {} - - void setSubentitiesCounts( SubdimensionTag, const typename MeshTraitsType::NeighborCountsArray& ) {} - void getSubentitiesCount( SubdimensionTag ) {} - void getSubentitiesMatrix( SubdimensionTag ) {} -}; - -template< typename MeshConfig, - typename Device > -class SubentityStorageLayer< MeshConfig, - Device, - Topologies::Polygon, - DimensionTag< Topologies::Polygon::dimension >, - false > + false, + dynamicTopology > { using MeshTraitsType = MeshTraits< MeshConfig, Device >; - using EntityTopology = Topologies::Polygon; using SubdimensionTag = DimensionTag< EntityTopology::dimension >; protected: diff --git a/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h index a26353156..4a15cf19e 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 EntityTopologyDimensionTag, + typename EntityDimensionTag, typename SuperdimensionTag, - bool SuperentityStorage = WeakSuperentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopologyDimensionTag::value >::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 EntityTopologyDimensionTag > + typename EntityDimensionTag > class SuperentityStorageLayerFamily : public SuperentityStorageLayer< MeshConfig, Device, - EntityTopologyDimensionTag, + EntityDimensionTag, DimensionTag< MeshTraits< MeshConfig, Device >::meshDimension > > { using BaseType = SuperentityStorageLayer< MeshConfig, Device, - EntityTopologyDimensionTag, + EntityDimensionTag, DimensionTag< MeshTraits< MeshConfig, Device >::meshDimension > >; using MeshTraitsType = MeshTraits< MeshConfig, Device >; @@ -57,7 +57,7 @@ protected: typename MeshTraitsType::NeighborCountsArray& getSuperentitiesCountsArray() { - static_assert( EntityTopologyDimensionTag::value < 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( EntityTopologyDimensionTag::value < 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( EntityTopologyDimensionTag::value < 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( EntityTopologyDimensionTag::value < 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 EntityTopologyDimensionTag, + typename EntityDimensionTag, typename SuperdimensionTag > -class SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, SuperdimensionTag, true > - : public SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SuperdimensionTag::Decrement > +class SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, SuperdimensionTag, true > + : public SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, typename SuperdimensionTag::Decrement > { - using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SuperdimensionTag::Decrement >; + using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, typename SuperdimensionTag::Decrement >; using MeshTraitsType = MeshTraits< MeshConfig, Device >; protected: @@ -111,7 +111,7 @@ protected: } template< typename Device_ > - SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SuperdimensionTag >& other ) + SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityDimensionTag, SuperdimensionTag >& other ) { operator=( other ); } @@ -125,7 +125,7 @@ protected: } template< typename Device_ > - SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SuperdimensionTag >& other ) + SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityDimensionTag, SuperdimensionTag >& other ) { BaseType::operator=( other ); superentitiesCounts = other.superentitiesCounts; @@ -137,7 +137,7 @@ protected: void print( std::ostream& str ) const { BaseType::print( str ); - str << "Adjacency matrix for superentities with dimension " << SuperdimensionTag::value << " of entities with dimension " << EntityTopologyDimensionTag::value << " 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 +186,12 @@ private: template< typename MeshConfig, typename Device, - typename EntityTopologyDimensionTag, + typename EntityDimensionTag, typename SuperdimensionTag > -class SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, SuperdimensionTag, false > - : public SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, typename SuperdimensionTag::Decrement > +class SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, SuperdimensionTag, false > + : public SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, typename SuperdimensionTag::Decrement > { - using BaseType = SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, 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 +201,18 @@ public: // termination of recursive inheritance (everything is reduced to EntityStorage == false thanks to the WeakSuperentityStorageTrait) template< typename MeshConfig, typename Device, - typename EntityTopologyDimensionTag > -class SuperentityStorageLayer< MeshConfig, Device, EntityTopologyDimensionTag, EntityTopologyDimensionTag, false > + typename EntityDimensionTag > +class SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, EntityDimensionTag, false > { - using SuperdimensionTag = EntityTopologyDimensionTag; + using SuperdimensionTag = EntityDimensionTag; protected: SuperentityStorageLayer() = default; explicit SuperentityStorageLayer( const SuperentityStorageLayer& other ) {} template< typename Device_ > - SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, SuperdimensionTag >& other ) {} + SuperentityStorageLayer( const SuperentityStorageLayer< MeshConfig, Device_, EntityDimensionTag, SuperdimensionTag >& other ) {} template< typename Device_ > - SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityTopologyDimensionTag, 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/MeshSubentityTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h index d9d43940e..4ba0defad 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h @@ -28,7 +28,7 @@ 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; @@ -58,15 +58,14 @@ public: }; }; -// Specialization for Polygons template< typename MeshConfig, typename Device, + typename EntityTopology, int Dimension > -class MeshSubentityTraits +class MeshSubentityTraits< MeshConfig, Device, EntityTopology, Dimension, true > { using GlobalIndexType = typename MeshConfig::GlobalIndexType; using LocalIndexType = typename MeshConfig::LocalIndexType; - using EntityTopology = Topologies::Polygon; public: static_assert( 0 <= Dimension && Dimension <= MeshConfig::meshDimension, "invalid dimension" ); diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h index 2b14337a4..b025436bf 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h @@ -23,14 +23,29 @@ #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 EntityTopology, + bool variableSize = std::is_same< EntityTopology, Topologies::Polygon >::value || + std::is_same< EntityTopology, Topologies::Polyhedron >::value > +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 Device, + typename EntityTopology, + int Dimension, + bool dynamicTopology = std::is_same< EntityTopology, Topologies::Polygon >::value || + std::is_same< EntityTopology, Topologies::Polyhedron >::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,14 +67,17 @@ 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 FaceSeedArrayType = Containers::Array< FaceSeedType, DeviceType, GlobalIndexType >; using CellSeedArrayType = Containers::Array< CellSeedType, DeviceType, GlobalIndexType >; using EntityTagsArrayType = Containers::Array< EntityTagType, DeviceType, GlobalIndexType >; diff --git a/src/TNL/Meshes/Topologies/Polyhedron.h b/src/TNL/Meshes/Topologies/Polyhedron.h new file mode 100644 index 000000000..03f5b7a09 --- /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 000000000..83edec194 --- /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 000000000..275be9d96 --- /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 000000000..2cd332194 --- /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/MeshTypeResolver.hpp b/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp index 58383c300..d2cf0e3a8 100644 --- a/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp +++ b/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp @@ -53,6 +53,10 @@ resolveCellTopology( Reader& reader, Functor&& functor ) 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) ); 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 7c71f5024..9f9de20ba 100644 --- a/src/TNL/Meshes/VTKTraits.h +++ b/src/TNL/Meshes/VTKTraits.h @@ -20,6 +20,9 @@ #include #include #include +#include +#include +#include namespace TNL { namespace Meshes { @@ -59,7 +62,8 @@ enum class EntityShape Voxel = 11, Hexahedron = 12, Wedge = 13, - Pyramid = 14 + Pyramid = 14, + Polyhedron = 100 }; inline std::string getShapeName( EntityShape shape ) @@ -94,6 +98,8 @@ inline std::string getShapeName( EntityShape shape ) return "Wedge"; case EntityShape::Pyramid: return "Pyramid"; + case EntityShape::Polyhedron: + return "Polyhedron"; } return ""; } @@ -116,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)) ); @@ -123,13 +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::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::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/Tools/tnl-mesh-converter.cpp b/src/Tools/tnl-mesh-converter.cpp index 30e19b508..b97639118 100644 --- a/src/Tools/tnl-mesh-converter.cpp +++ b/src/Tools/tnl-mesh-converter.cpp @@ -41,9 +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::Polygon > { 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/UnitTests/Meshes/MeshTest.h b/src/UnitTests/Meshes/MeshTest.h index 63245e86a..040eb07e9 100644 --- a/src/UnitTests/Meshes/MeshTest.h +++ b/src/UnitTests/Meshes/MeshTest.h @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include "EntityTests.h" @@ -70,7 +73,26 @@ public: static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } }; -//struct TestMeshConfigTag {}; +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 ) @@ -1020,7 +1042,7 @@ TEST( MeshTest, TwoPolygonsTest ) | | | | | polygon0 | - | (rectangle) | + | (quad) | edge3 edge1 | | |____________________| @@ -1652,6 +1674,2050 @@ TEST( MeshTest, SevenPolygonsTest ) 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.setPointsCount( 8 ); + 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.setCellsCount( 2 ); + + 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.setPointsCount( 6 ); + 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.setCellsCount( 2 ); + + 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.setPointsCount( 22 ); + 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: indeces refer to the points + */ + + meshBuilder.setFacesCount( 16 ); + + // 0 1 2 3 4 + meshBuilder.getFaceSeed( 0 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 6 ); + 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 ).setCornersCount( 3 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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: indeces refer to the faces + */ + + meshBuilder.setCellsCount( 2 ); + + // 0 1 2 3 4 5 6 7 8 + meshBuilder.getCellSeed( 0 ).setCornersCount( 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 ); + + // 9 10 11 12 13 5 14 15 + meshBuilder.getCellSeed( 1 ).setCornersCount( 8 ); + 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 -- GitLab From 9f5c2dda27450349e996cf10e5cddebbcc40d622 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Mon, 24 May 2021 23:25:01 +0200 Subject: [PATCH 13/42] Added FPMAReader, FPMAWriter + refactoring --- src/TNL/Meshes/MeshDetails/ConfigValidator.h | 4 + .../initializer/SubentitySeedsCreator.h | 136 +++++++------- .../layers/SubentityStorageLayer.h | 23 ++- .../MeshDetails/traits/MeshSubentityTraits.h | 13 +- .../Meshes/MeshDetails/traits/MeshTraits.h | 4 +- src/TNL/Meshes/Readers/FPMAReader.h | 168 ++++++++++++++++++ src/TNL/Meshes/Readers/MeshReader.h | 41 ++++- src/TNL/Meshes/Readers/NetgenReader.h | 4 +- src/TNL/Meshes/Readers/VTKReader.h | 8 +- src/TNL/Meshes/Readers/VTUReader.h | 8 +- src/TNL/Meshes/Readers/getMeshReader.h | 3 + src/TNL/Meshes/Topologies/isDynamicTopology.h | 38 ++++ src/TNL/Meshes/TypeResolver/BuildConfigTags.h | 7 + .../Meshes/TypeResolver/MeshTypeResolver.hpp | 2 + src/TNL/Meshes/Writers/FPMAWriter.h | 56 ++++++ src/TNL/Meshes/Writers/FPMAWriter.hpp | 87 +++++++++ 16 files changed, 510 insertions(+), 92 deletions(-) create mode 100644 src/TNL/Meshes/Readers/FPMAReader.h create mode 100644 src/TNL/Meshes/Topologies/isDynamicTopology.h create mode 100644 src/TNL/Meshes/Writers/FPMAWriter.h create mode 100644 src/TNL/Meshes/Writers/FPMAWriter.hpp diff --git a/src/TNL/Meshes/MeshDetails/ConfigValidator.h b/src/TNL/Meshes/MeshDetails/ConfigValidator.h index 665574c0d..cb439b567 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/SubentitySeedsCreator.h b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h index 3609211b4..57a17297f 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h +++ b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h @@ -70,6 +70,38 @@ public: } }; +template< typename MeshConfig, + 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< 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 > >; + + 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; + } + + constexpr static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + return SubentityTraits::count; + } +}; + template< typename MeshConfig > class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 1 > > { @@ -112,6 +144,42 @@ public: } }; +template< typename MeshConfig > +class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, 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 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 SubentitySeedArray = Containers::Array< EntitySeed< MeshConfig, SubentityTopology >, Devices::Host, LocalIndexType >; + + static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + { + const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); + const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); + + SubentitySeedArray seeds; + seeds.setSize( subverticesCount ); + + for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) + seeds[ i ].setCornerId( 0, subvertices.getColumnIndex( i ) ); + + return seeds; + } + + 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 > > { @@ -290,73 +358,5 @@ public: } }; -template< typename MeshConfig, - 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< 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 > >; - - 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; - } - - constexpr static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) - { - return SubentityTraits::count; - } -}; - -template< typename MeshConfig > -class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, 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 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 SubentitySeedArray = Containers::Array< EntitySeed< MeshConfig, SubentityTopology >, Devices::Host, LocalIndexType >; - - static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) - { - const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); - const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); - - SubentitySeedArray seeds; - seeds.setSize( subverticesCount ); - - for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) - seeds[ i ].setCornerId( 0, subvertices.getColumnIndex( i ) ); - - return seeds; - } - - static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) - { - return mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); - } -}; - } // namespace Meshes } // namespace TNL diff --git a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h index ef09162c0..b7b81fad6 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -20,8 +20,6 @@ #include #include #include -#include -#include namespace TNL { namespace Meshes { @@ -31,8 +29,7 @@ template< typename MeshConfig, typename EntityTopology, typename SubdimensionTag, bool SubentityStorage = WeakSubentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopology::dimension >::EntityTopology, SubdimensionTag >::storageEnabled, - bool dynamicTopology = std::is_same< EntityTopology, Topologies::Polygon >::value || - std::is_same< EntityTopology, Topologies::Polyhedron >::value > + bool DynamicTopology = Topologies::isDynamicTopology< EntityTopology >::value > class SubentityStorageLayer; template< typename MeshConfig, @@ -87,6 +84,12 @@ protected: } }; +/**** + * Mesh subentity storage layer with specializations + * + * SUBENTITY STORAGE DYNAMIC TOPOLOGY + * TRUE FALSE + */ template< typename MeshConfig, typename Device, typename EntityTopology, @@ -183,6 +186,12 @@ private: friend class SubentityStorageLayer; }; +/**** + * Mesh subentity storage layer with specializations + * + * SUBENTITY STORAGE DYNAMIC TOPOLOGY + * TRUE TRUE + */ template< typename MeshConfig, typename Device, typename EntityTopology, @@ -297,6 +306,12 @@ private: friend class SubentityStorageLayer; }; +/**** + * Mesh subentity storage layer with specializations + * + * SUBENTITY STORAGE DYNAMIC TOPOLOGY + * FALSE TRUE/FALSE + */ template< typename MeshConfig, typename Device, typename EntityTopology, diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h index 4ba0defad..7ab39d200 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h @@ -19,11 +19,16 @@ #include #include #include -#include namespace TNL { namespace Meshes { +/**** + * Mesh subentity traits with specializations + * + * DYNAMIC TOPOLOGY + * FALSE + */ template< typename MeshConfig, typename Device, typename EntityTopology, @@ -58,6 +63,12 @@ public: }; }; +/**** + * Mesh subentity traits with specializations + * + * DYNAMIC TOPOLOGY + * TRUE + */ template< typename MeshConfig, typename Device, typename EntityTopology, diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h index b025436bf..c596eaf55 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace TNL { namespace Meshes { @@ -42,8 +43,7 @@ template< typename MeshConfig, typename Device, typename EntityTopology, int Dimension, - bool dynamicTopology = std::is_same< EntityTopology, Topologies::Polygon >::value || - std::is_same< EntityTopology, Topologies::Polyhedron >::value > + bool dynamicTopology = Topologies::isDynamicTopology< EntityTopology >::value > class MeshSubentityTraits; template< typename MeshConfig, typename Device, typename MeshEntity, int Superdimension > class MeshSuperentityTraits; diff --git a/src/TNL/Meshes/Readers/FPMAReader.h b/src/TNL/Meshes/Readers/FPMAReader.h new file mode 100644 index 000000000..6fce654f5 --- /dev/null +++ b/src/TNL/Meshes/Readers/FPMAReader.h @@ -0,0 +1,168 @@ +#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 + 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 + nextLine( inputFile, iss, line ); + iss >> NumberOfPoints; + + // read points + nextLine( inputFile, iss, line ); + 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++ ) { + double aux; + iss >> aux; + if( ! iss ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read " + std::to_string(i) + "th component of the vertex number " + std::to_string(pointIndex) + "." ); + } + + pointsArray.push_back( aux ); + } + } + + // read number of faces + nextLine( inputFile, iss, line ); + iss >> NumberOfFaces; + + // read faces + for( std::size_t faceIndex = 0; faceIndex < NumberOfFaces; faceIndex++ ) { + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read enough faces, the file may be invalid or corrupted." ); + } + + // read number of points of a face + size_t numberOfFacePoints; + nextLine( inputFile, iss, line ); + iss >> numberOfFacePoints; + + // read points of a face + for( std::size_t i = 0; i < numberOfFacePoints; i++ ) { + if( ! iss ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read " + std::to_string(i) + "th component of the face number " + std::to_string(faceIndex) + "." ); + } + + std::uint32_t pointIndex; + iss >> pointIndex; + + if( ! iss || pointIndex >= NumberOfPoints ) { + reset(); + throw MeshReaderError( "FPMAReader", std::to_string(i) + "th component of the face number " + std::to_string(faceIndex) + " is invalid." ); + } + + faceConnectivityArray.emplace_back( pointIndex ); + } + + faceOffsetsArray.emplace_back( faceConnectivityArray.size() ); + } + + // read number of cells + nextLine( inputFile, iss, line ); + iss >> NumberOfCells; + + // read faces + for( std::size_t cellIndex = 0; cellIndex < NumberOfCells; cellIndex++ ) { + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read enough cells, the file may be invalid or corrupted." ); + } + + // read number of faces of a cell + size_t numberOfCellFaces; + nextLine( inputFile, iss, line ); + iss >> numberOfCellFaces; + + // read faces of a cell + for( std::size_t i = 0; i < numberOfCellFaces; i++ ) { + if( ! iss ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read " + std::to_string(i) + "th component of the cell number " + std::to_string(cellIndex) + "." ); + } + + std::uint32_t faceIndex; + iss >> faceIndex; + + if( ! iss || faceIndex >= NumberOfFaces ) { + reset(); + throw MeshReaderError( "FPMAReader", std::to_string(i) + "th component of the cell number " + std::to_string(faceIndex) + " is invalid." ); + } + + 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: + void nextLine( std::ifstream& inputFile, std::istringstream& iss, std::string& line ) + { + iss.clear(); + // get next non-empty line, that isn't a comment + while( std::getline( inputFile, line ) && ( line.empty() || line[0] == '#' ) ) {} + iss.str( line ); + } +}; + +} // namespace Readers +} // namespace Meshes +} // namespace TNL diff --git a/src/TNL/Meshes/Readers/MeshReader.h b/src/TNL/Meshes/Readers/MeshReader.h index 5595fac62..f1188de71 100644 --- a/src/TNL/Meshes/Readers/MeshReader.h +++ b/src/TNL/Meshes/Readers/MeshReader.h @@ -168,10 +168,12 @@ public: using MeshBuilder = MeshBuilder< MeshType >; using PointType = typename MeshType::PointType; + using FaceSeedType = typename MeshBuilder::FaceSeedType; using CellSeedType = typename MeshBuilder::CellSeedType; MeshBuilder meshBuilder; meshBuilder.setPointsCount( NumberOfPoints ); + meshBuilder.setFacesCount( NumberOfFaces ); meshBuilder.setCellsCount( NumberOfCells ); // assign points @@ -190,11 +192,29 @@ 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 ); + std::size_t offsetStart = 0; + for( std::size_t i = 0; i < NumberOfFaces; i++ ) { + FaceSeedType& seed = meshBuilder.getFaceSeed( i ); + const std::size_t offsetEnd = offsets[ i ]; + seed.setCornersCount( offsetEnd - offsetStart ); + 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 ); std::size_t offsetStart = 0; for( std::size_t i = 0; i < NumberOfCells; i++ ) { CellSeedType& seed = meshBuilder.getCellSeed( i ); @@ -205,11 +225,11 @@ public: 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" ); @@ -224,7 +244,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 @@ -279,7 +299,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; @@ -289,21 +309,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 432776ec4..51a1737b8 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 aeb69300d..4e78d43e1 100644 --- a/src/TNL/Meshes/Readers/VTKReader.h +++ b/src/TNL/Meshes/Readers/VTKReader.h @@ -162,9 +162,11 @@ public: //TODO: uncomment line below later for polyhedrals //using PolyhedralShapeGroupChecker = VTK::EntityShapeGroupChecker< VTK::EntityShape::Polyhedral >; cellShape = (VTK::EntityShape) cellTypes[0]; + for( auto c : cellTypes ) { - if( (VTK::EntityShape) c != entityShape ) + 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 ) ) @@ -229,8 +231,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 c4ccaef5e..08450b0fe 100644 --- a/src/TNL/Meshes/Readers/VTUReader.h +++ b/src/TNL/Meshes/Readers/VTUReader.h @@ -50,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" ) ); @@ -135,7 +135,7 @@ class VTUReader max_offset = c; } }, - offsetsArray + cellOffsetsArray ); // validate connectivity visit( [this, max_offset](auto&& array) { @@ -146,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 41976dcfd..4003ec6f1 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 000000000..fcf99ac94 --- /dev/null +++ b/src/TNL/Meshes/Topologies/isDynamicTopology.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include + +namespace TNL { +namespace Meshes { +namespace Topologies { + +template < typename Topology, int SubDimension, typename = int > +struct SubtopologyHasCount : std::false_type +{}; + +template < typename Topology, int SubDimension > +struct SubtopologyHasCount< Topology, SubDimension, decltype(Subtopology< Topology, SubDimension >::count, int{}) > : std::true_type +{}; + +template< typename Topology, int Dimension = Topology::dimension > +struct isDynamicTopology +{ + enum : bool { value = !SubtopologyHasCount< Topology, Dimension - 1 >::value || + isDynamicTopology< Topology, Dimension - 1 >::value }; +}; + +template<> +struct isDynamicTopology< Vertex, 0 > : std::false_type +{}; + +template< typename Topology > +struct isDynamicTopology< Topology, 1 > +{ + enum : bool { value = !SubtopologyHasCount< Topology, 0 >::value }; +}; + +} // 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 dd83a017a..413e7538a 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 d2cf0e3a8..f6c991f41 100644 --- a/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp +++ b/src/TNL/Meshes/TypeResolver/MeshTypeResolver.hpp @@ -57,6 +57,8 @@ resolveCellTopology( Reader& reader, Functor&& functor ) 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/Writers/FPMAWriter.h b/src/TNL/Meshes/Writers/FPMAWriter.h new file mode 100644 index 000000000..19f6a7dc5 --- /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 000000000..99ecb0ab0 --- /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 -- GitLab From 5308a1505bf7c6c5c29d8903be46fcd84529fe01 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Mon, 7 Jun 2021 23:52:17 +0200 Subject: [PATCH 14/42] Added new getEntityMeasure specializations and function isPlanar for 3D polygons + refactoring - added getEntityMeasure specializations for 2D and 3D polygon, pyramid, wedge, polyhedron - added unit tests for new getEntityMeasure specializations - added function isPlanar for checking whether all points of a 3D polygon are on the same plane - added unit test for function isPlanar - refactored isDynamicTopology type trait to avoid warning --- src/TNL/Meshes/Geometry/getEntityCenter.h | 2 +- src/TNL/Meshes/Geometry/getEntityMeasure.h | 177 +++++++ .../Meshes/Geometry/getOutwardNormalVector.h | 32 +- src/TNL/Meshes/Geometry/isPlanar.h | 34 ++ .../MeshDetails/initializer/EntitySeed.h | 4 +- .../layers/SubentityStorageLayer.h | 2 +- .../Meshes/MeshDetails/traits/MeshTraits.h | 4 +- src/TNL/Meshes/Topologies/IsDynamicTopology.h | 39 ++ src/TNL/Meshes/Topologies/isDynamicTopology.h | 38 -- src/TNL/TypeTraits.h | 17 + src/UnitTests/Meshes/CMakeLists.txt | 12 +- src/UnitTests/Meshes/MeshGeometryTest.cpp | 2 + src/UnitTests/Meshes/MeshGeometryTest.cu | 2 + src/UnitTests/Meshes/MeshGeometryTest.h | 457 ++++++++++++++++++ 14 files changed, 767 insertions(+), 55 deletions(-) create mode 100644 src/TNL/Meshes/Geometry/isPlanar.h create mode 100644 src/TNL/Meshes/Topologies/IsDynamicTopology.h delete mode 100644 src/TNL/Meshes/Topologies/isDynamicTopology.h create mode 100644 src/UnitTests/Meshes/MeshGeometryTest.cpp create mode 100644 src/UnitTests/Meshes/MeshGeometryTest.cu create mode 100644 src/UnitTests/Meshes/MeshGeometryTest.h diff --git a/src/TNL/Meshes/Geometry/getEntityCenter.h b/src/TNL/Meshes/Geometry/getEntityCenter.h index addef6b9f..031bd62e8 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 fb1e2d468..6debfbec6 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,177 @@ 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) + + 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 ); +} + } // namespace Meshes } // namespace TNL diff --git a/src/TNL/Meshes/Geometry/getOutwardNormalVector.h b/src/TNL/Meshes/Geometry/getOutwardNormalVector.h index 6221236f5..c5b6a8243 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/isPlanar.h b/src/TNL/Meshes/Geometry/isPlanar.h new file mode 100644 index 000000000..8f50ee5a9 --- /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/MeshDetails/initializer/EntitySeed.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h index 6db4eed70..04143e2a3 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeed.h @@ -141,8 +141,8 @@ public: { 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" ); + /*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 ); } diff --git a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h index b7b81fad6..08861bd23 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -29,7 +29,7 @@ template< typename MeshConfig, typename EntityTopology, typename SubdimensionTag, bool SubentityStorage = WeakSubentityStorageTrait< MeshConfig, Device, typename MeshTraits< MeshConfig, Device >::template EntityTraits< EntityTopology::dimension >::EntityTopology, SubdimensionTag >::storageEnabled, - bool DynamicTopology = Topologies::isDynamicTopology< EntityTopology >::value > + bool IsDynamicTopology = Topologies::IsDynamicTopology< EntityTopology >::value > class SubentityStorageLayer; template< typename MeshConfig, diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h index c596eaf55..d2f128f8e 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include namespace TNL { namespace Meshes { @@ -43,7 +43,7 @@ template< typename MeshConfig, typename Device, typename EntityTopology, int Dimension, - bool dynamicTopology = Topologies::isDynamicTopology< EntityTopology >::value > + bool IsDynamicTopology = Topologies::IsDynamicTopology< EntityTopology >::value > class MeshSubentityTraits; template< typename MeshConfig, typename Device, typename MeshEntity, int Superdimension > class MeshSuperentityTraits; diff --git a/src/TNL/Meshes/Topologies/IsDynamicTopology.h b/src/TNL/Meshes/Topologies/IsDynamicTopology.h new file mode 100644 index 000000000..0cb52358a --- /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/isDynamicTopology.h b/src/TNL/Meshes/Topologies/isDynamicTopology.h deleted file mode 100644 index fcf99ac94..000000000 --- a/src/TNL/Meshes/Topologies/isDynamicTopology.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace TNL { -namespace Meshes { -namespace Topologies { - -template < typename Topology, int SubDimension, typename = int > -struct SubtopologyHasCount : std::false_type -{}; - -template < typename Topology, int SubDimension > -struct SubtopologyHasCount< Topology, SubDimension, decltype(Subtopology< Topology, SubDimension >::count, int{}) > : std::true_type -{}; - -template< typename Topology, int Dimension = Topology::dimension > -struct isDynamicTopology -{ - enum : bool { value = !SubtopologyHasCount< Topology, Dimension - 1 >::value || - isDynamicTopology< Topology, Dimension - 1 >::value }; -}; - -template<> -struct isDynamicTopology< Vertex, 0 > : std::false_type -{}; - -template< typename Topology > -struct isDynamicTopology< Topology, 1 > -{ - enum : bool { value = !SubtopologyHasCount< Topology, 0 >::value }; -}; - -} // namespace Topologies -} // namespace Meshes -} // namespace TNL \ No newline at end of file diff --git a/src/TNL/TypeTraits.h b/src/TNL/TypeTraits.h index 8abb28c6a..31505dd78 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/UnitTests/Meshes/CMakeLists.txt b/src/UnitTests/Meshes/CMakeLists.txt index 86cb34d5c..b6675b366 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 ${CXX_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,13 +41,18 @@ 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 ) diff --git a/src/UnitTests/Meshes/MeshGeometryTest.cpp b/src/UnitTests/Meshes/MeshGeometryTest.cpp new file mode 100644 index 000000000..1c8d06ffd --- /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 000000000..1c8d06ffd --- /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 000000000..7766e6301 --- /dev/null +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -0,0 +1,457 @@ +#pragma once + +#ifdef HAVE_GTEST +#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::Polyhedron > +{ +public: + 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.setPointsCount( 5 ); + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + + meshBuilder.setCellsCount( 1 ); + + meshBuilder.getCellSeed( 0 ).setCornersCount( 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 PolyhedronTestMesh = Mesh< TestPolygon3DMeshConfig >; + using PolyhedronMeshEntityType = MeshEntity< TestPolygon3DMeshConfig, Devices::Host, Topologies::Polyhedron >; + using VertexMeshEntityType = typename PolyhedronMeshEntityType::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 ); + + PolyhedronTestMesh mesh; + MeshBuilder< PolyhedronTestMesh > meshBuilder; + + meshBuilder.setPointsCount( 5 ); + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + + meshBuilder.setFacesCount( 1 ); + meshBuilder.getFaceSeed( 0 ).setCornersCount( 5 ); + 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 ); + + meshBuilder.setCellsCount( 1 ); + meshBuilder.getCellSeed( 0 ).setCornersCount( 1 ); + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); + + 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.setPointsCount( 6 ); + 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.setCellsCount( 1 ); + 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.setPointsCount( 5 ); + meshBuilder.setPoint( 0, point0 ); + meshBuilder.setPoint( 1, point1 ); + meshBuilder.setPoint( 2, point2 ); + meshBuilder.setPoint( 3, point3 ); + meshBuilder.setPoint( 4, point4 ); + + meshBuilder.setCellsCount( 1 ); + 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.setPointsCount( 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.setFacesCount( 9 ); + + meshBuilder.getFaceSeed( 0 ).setCornersCount( 4 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 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 ).setCornersCount( 3 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 0, 4 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 1, 5 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 2, 8 ); + + meshBuilder.getFaceSeed( 6 ).setCornersCount( 3 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 0, 5 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 1, 7 ); + meshBuilder.getFaceSeed( 6 ).setCornerId( 2, 8 ); + + meshBuilder.getFaceSeed( 7 ).setCornersCount( 3 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 0, 7 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 1, 6 ); + meshBuilder.getFaceSeed( 7 ).setCornerId( 2, 8 ); + + meshBuilder.getFaceSeed( 8 ).setCornersCount( 3 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 0, 6 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 1, 4 ); + meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 8 ); + + meshBuilder.setCellsCount( 1 ); + meshBuilder.getCellSeed( 0 ).setCornersCount( 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 PolyhedronTestMesh = Mesh< TestPolygon3DMeshConfig >; + using PolyhedronMeshEntityType = MeshEntity< TestPolygon3DMeshConfig, Devices::Host, Topologies::Polyhedron >; + using VertexMeshEntityType = typename PolyhedronMeshEntityType::SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + using RealType = typename PolyhedronTestMesh::RealType; + + constexpr RealType 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[0] + offset[0], point0[1] + offset[1], point0[2] + offset[2] ), + point1_( point1[0] + offset[0], point1[1] + offset[1], point1[2] + offset[2] ), + point2_( point2[0] + offset[0], point2[1] + offset[1], point2[2] + offset[2] ), + point3_( point3[0] + offset[0], point3[1] + offset[1], point3[2] + offset[2] ), + point4_( point4[0] + offset[0], point4[1] + offset[1], point4[2] + offset[2] ); + + PolyhedronTestMesh mesh; + MeshBuilder< PolyhedronTestMesh > meshBuilder; + + meshBuilder.setPointsCount( 10 ); + 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.setFacesCount( 6 ); + + // Planar face with non-deviated points + meshBuilder.getFaceSeed( 0 ).setCornersCount( 5 ); + 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 ); + + // Non-Planar face with 0th point deviated + meshBuilder.getFaceSeed( 1 ).setCornersCount( 5 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 0, 5 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 3, 3 ); + meshBuilder.getFaceSeed( 1 ).setCornerId( 4, 4 ); + + // Non-Planar face with 1th point deviated + meshBuilder.getFaceSeed( 2 ).setCornersCount( 5 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 0, 0 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 1, 6 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 3, 3 ); + meshBuilder.getFaceSeed( 2 ).setCornerId( 4, 4 ); + + // Non-Planar face with 2th point deviated + meshBuilder.getFaceSeed( 3 ).setCornersCount( 5 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 0, 0 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 2, 7 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 3, 3 ); + meshBuilder.getFaceSeed( 3 ).setCornerId( 4, 4 ); + + // Non-Planar face with 3th point deviated + meshBuilder.getFaceSeed( 4 ).setCornersCount( 5 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 0, 0 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 3, 8 ); + meshBuilder.getFaceSeed( 4 ).setCornerId( 4, 4 ); + + // Non-Planar face with 4th point deviated + meshBuilder.getFaceSeed( 5 ).setCornersCount( 5 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 0, 0 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 1, 1 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 2, 2 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 3, 3 ); + meshBuilder.getFaceSeed( 5 ).setCornerId( 4, 9 ); + + meshBuilder.setCellsCount( 1 ); + meshBuilder.getCellSeed( 0 ).setCornersCount( 6 ); + 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_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 ); +} + +} // namespace MeshTest + +#endif -- GitLab From e31a3146de63601196124af830eb4230f7fc0ac3 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Sat, 19 Jun 2021 12:24:42 +0200 Subject: [PATCH 15/42] Added new functions into Meshes/Geometry: - modified getEntityMeasure specialization for polyhedrons to remove restriction regarding the ordering of vertices, but now it only works for convex polyhedrons - added function for decomposing polygonal mesh into triangular mesh - added function for decomposing polyhedral mesh into tetrahedral mesh --- src/TNL/Meshes/Geometry/getDecomposedMesh.h | 621 ++++++++++++++++++++ src/TNL/Meshes/Geometry/getEntityMeasure.h | 32 +- src/UnitTests/Meshes/MeshGeometryTest.h | 415 +++++++++++++ 3 files changed, 1067 insertions(+), 1 deletion(-) create mode 100644 src/TNL/Meshes/Geometry/getDecomposedMesh.h diff --git a/src/TNL/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h new file mode 100644 index 000000000..4a97425e0 --- /dev/null +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -0,0 +1,621 @@ +#pragma once + +#include +#include +#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; +}; + +enum class GetTriangleMeshVersion +{ + V1, V2 +}; + +/** + * Triangles are made by connecting each edge to the centroid of cell. + */ +template< typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true > +auto +getTriangleMesh_v1( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + using TriangleMeshConfig = TriangleConfig< MeshConfig >; + using TriangleMesh = Mesh< TriangleMeshConfig, Devices::Host >; + using GlobalIndexType = typename TriangleMesh::GlobalIndexType; + using LocalIndexType = typename TriangleMesh::LocalIndexType; + + TriangleMesh outMesh; + MeshBuilder< TriangleMesh > meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 2 >(); + + // find the number of points and cells in the outMesh + GlobalIndexType outPointsCount = inPointsCount; + GlobalIndexType outCellsCount = 0; + + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 2 >( i ); + const auto verticesCount = cell.template getSubentitiesCount< 0 >(); + if( verticesCount == 3 ) { // cell is not decomposed as it's already a triangle + outCellsCount++; // cell is just copied + } + else { // cell is decomposed as it has got more than 3 vertices + outPointsCount++; // each decomposed cell has 1 new center point + outCellsCount += verticesCount; // cell is decomposed into verticesCount number of triangles + } + } + + meshBuilder.setPointsCount( outPointsCount ); + meshBuilder.setCellsCount( outCellsCount ); + + // copy the points from inMesh to outMesh + GlobalIndexType pointSetIdx = 0; + for( ; pointSetIdx < inPointsCount; pointSetIdx++ ) { + meshBuilder.setPoint( pointSetIdx, inMesh.getPoint( pointSetIdx ) ); + } + + for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 2 >( i ); + const auto verticesCount = cell.template getSubentitiesCount< 0 >(); + if( verticesCount == 3 ) { // cell is not decomposed as it's already a triangle + // copy cell + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + cellSeed.setCornerId( 0, cell.template getSubentityIndex< 0 >( 0 ) ); + cellSeed.setCornerId( 1, cell.template getSubentityIndex< 0 >( 1 ) ); + cellSeed.setCornerId( 2, cell.template getSubentityIndex< 0 >( 2 ) ); + } + else { // cell is decomposed as it has got more than 3 vertices + // add centroid of cell to outMesh + const auto cellCenter = getEntityCenter( inMesh, cell ); + const auto cellCenterIdx = pointSetIdx++; + meshBuilder.setPoint( cellCenterIdx, cellCenter ); + // decompose cell into triangles by connecting each edge to the centroid + for( LocalIndexType j = 0, k = 1; k < verticesCount; j++, k++ ) { + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + cellSeed.setCornerId( 0, cell.template getSubentityIndex< 0 >( j ) ); + cellSeed.setCornerId( 1, cell.template getSubentityIndex< 0 >( k ) ); + cellSeed.setCornerId( 2, cellCenterIdx ); + } + { // wrap around term + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + cellSeed.setCornerId( 0, cell.template getSubentityIndex< 0 >( verticesCount - 1 ) ); + cellSeed.setCornerId( 1, cell.template getSubentityIndex< 0 >( 0 ) ); + cellSeed.setCornerId( 2, cellCenterIdx ); + } + } + } + + meshBuilder.build( outMesh ); + return outMesh; +} + +/** + * Triangles are made by choosing the 0th point of cell and connecting each non-adjacent edge to it. + */ +template< typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true > +auto +getTriangleMesh_v2( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + using TriangleMeshConfig = TriangleConfig< MeshConfig >; + using TriangleMesh = Mesh< TriangleMeshConfig, Devices::Host >; + using GlobalIndexType = typename TriangleMesh::GlobalIndexType; + using LocalIndexType = typename TriangleMesh::LocalIndexType; + + TriangleMesh outMesh; + MeshBuilder< TriangleMesh > meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 2 >(); + + // outMesh keeps all the points of inMesh + meshBuilder.setPointsCount( inPointsCount ); + for( GlobalIndexType i = 0; i < inPointsCount; i++ ) { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); + } + + // find the number of cells in the outMesh + GlobalIndexType outCellsCount = 0; + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 2 >( i ); + const auto verticesCount = cell.template getSubentitiesCount< 0 >(); + outCellsCount += verticesCount - 2; + } + meshBuilder.setCellsCount( outCellsCount ); + + for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 2 >( i ); + const auto verticesCount = cell.template getSubentitiesCount< 0 >(); + const auto v0 = cell.template getSubentityIndex< 0 >( 0 ); + for( LocalIndexType j = 1, k = 2; k < verticesCount; j++, k++ ) { + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + const auto v1 = cell.template getSubentityIndex< 0 >( j ); + const auto v2 = cell.template getSubentityIndex< 0 >( k ); + cellSeed.setCornerId( 0, v0 ); + cellSeed.setCornerId( 1, v1 ); + cellSeed.setCornerId( 2, v2 ); + } + } + + meshBuilder.build( outMesh ); + return outMesh; +} + +template< GetTriangleMeshVersion version, + typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true > +auto +getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + switch( version ) + { + case GetTriangleMeshVersion::V1: return getTriangleMesh_v1( inMesh ); + case GetTriangleMeshVersion::V2: return getTriangleMesh_v2( inMesh ); + } +} + +// Polyhedral Mesh +template< typename ParentConfig > +struct TetrahedronConfig: public ParentConfig +{ + using CellTopology = Topologies::Tetrahedron; +}; + +enum class GetTetrahedronMeshVersion +{ + V1, V2, V3, V4, V5 +}; + +/** + * Tetrahedrons are made by connecting the triangles of faces to the centroid of cell. + * Triangles of a face are made by connecting each edge to the centroid of a face. + */ +template< typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > +auto +getTetrahedronMesh_v1( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; + using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; + using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; + using LocalIndexType = typename TetrahedronMesh::LocalIndexType; + + TetrahedronMesh outMesh; + MeshBuilder< TetrahedronMesh > meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); + + // count the number of points and cells in the outMesh + GlobalIndexType outPointsCount = inPointsCount + inCellsCount; // for each cell, there is a new point (centroid of cell) + GlobalIndexType outCellsCount = 0; + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + const auto facesCount = cell.template getSubentitiesCount< 2 >(); + for( LocalIndexType j = 0; j < facesCount; j++ ) { + const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto face = inMesh.template getEntity< 2 >( faceIdx ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + if( verticesCount == 3 ) { // face is not decomposed as it's already a triangle + outCellsCount++; + } + else { // face is decomposed as it has got more than 3 vertices + outPointsCount++; // for each face of cell, there is a new point (centroid of face) + outCellsCount += verticesCount; // there is verticesCount number of tetrahedrons per face + } + } + } + meshBuilder.setPointsCount( outPointsCount ); + meshBuilder.setCellsCount( outCellsCount ); + + // copy the points from inMesh to outMesh + GlobalIndexType pointSetIdx = 0; + for( ; pointSetIdx < inPointsCount; pointSetIdx++ ) { + meshBuilder.setPoint( pointSetIdx, inMesh.getPoint( pointSetIdx ) ); + } + + // set up cell seeds for the outMesh + for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + + // centroid of the cell connects to triangles of its faces, making tetrahedrons + const auto cellCenter = getEntityCenter( inMesh, cell ); + const auto cellCenterIdx = pointSetIdx++; + meshBuilder.setPoint( cellCenterIdx, cellCenter ); + + const auto facesCount = cell.template getSubentitiesCount< 2 >(); + for( LocalIndexType j = 0; j < facesCount; j++ ) { + const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto face = inMesh.template getEntity< 2 >( faceIdx ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + + if( verticesCount == 3 ) { // face is a triangle + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + cellSeed.setCornerId( 0, face.template getSubentityIndex< 0 >( 0 ) ); + cellSeed.setCornerId( 1, face.template getSubentityIndex< 0 >( 1 ) ); + cellSeed.setCornerId( 2, face.template getSubentityIndex< 0 >( 2 ) ); + cellSeed.setCornerId( 3, cellCenterIdx ); + } + else { // face is decomposed into triangles as it has got more than 3 vertices + // centroid of the face connects to its edges, making triangles + const auto faceCenter = getEntityCenter( inMesh, face ); + const auto faceCenterIdx = pointSetIdx++; + meshBuilder.setPoint( faceCenterIdx, faceCenter ); + + for( LocalIndexType k = 0, m = 1; m < verticesCount; k++, m++ ) { + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + cellSeed.setCornerId( 0, face.template getSubentityIndex< 0 >( k ) ); + cellSeed.setCornerId( 1, face.template getSubentityIndex< 0 >( m ) ); + cellSeed.setCornerId( 2, faceCenterIdx ); + cellSeed.setCornerId( 3, cellCenterIdx ); + } + { // wrap around term + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + cellSeed.setCornerId( 0, face.template getSubentityIndex< 0 >( verticesCount - 1 ) ); + cellSeed.setCornerId( 1, face.template getSubentityIndex< 0 >( 0 ) ); + cellSeed.setCornerId( 2, faceCenterIdx ); + cellSeed.setCornerId( 3, cellCenterIdx ); + } + } + } + } + + meshBuilder.build( outMesh ); + return outMesh; +} + +/** + * Tetrahedrons are made by connecting the triangles of faces to the centroid of cell. + * Triangles of a face are made by choosing the 0th point of a face and connecting each of its non-adjacent edges to it. + */ +template< typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > +auto +getTetrahedronMesh_v2( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; + using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; + using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; + using LocalIndexType = typename TetrahedronMesh::LocalIndexType; + + TetrahedronMesh outMesh; + MeshBuilder< TetrahedronMesh > meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); + + // count the number of points and cells in the outMesh + GlobalIndexType outPointsCount = inPointsCount + inCellsCount; // for each cell, there is a new point (centroid of cell) + GlobalIndexType outCellsCount = 0; + + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + const auto facesCount = cell.template getSubentitiesCount< 2 >(); + + for( LocalIndexType j = 0; j < facesCount; j++ ) { + const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto face = inMesh.template getEntity< 2 >( faceIdx ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + outCellsCount += verticesCount - 2; // there is verticesCount - 2 number of tetrahedrons per face + } + } + meshBuilder.setPointsCount( outPointsCount ); + meshBuilder.setCellsCount( outCellsCount ); + + // copy the points from inMesh to outMesh + GlobalIndexType pointSetIdx = 0; + for( ; pointSetIdx < inPointsCount; pointSetIdx++ ) { + meshBuilder.setPoint( pointSetIdx, inMesh.getPoint( pointSetIdx ) ); + } + + // set up cell seeds for the outMesh + for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + + // centroid of the cell connects to triangles of its faces, making tetrahedrons + const auto cellCenter = getEntityCenter( inMesh, cell ); + const auto cellCenterIdx = pointSetIdx++; + meshBuilder.setPoint( cellCenterIdx, cellCenter ); + + const auto facesCount = cell.template getSubentitiesCount< 2 >(); + for( LocalIndexType j = 0; j < facesCount; j++ ) { + const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto face = inMesh.template getEntity< 2 >( faceIdx ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + const auto v0 = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles + for( LocalIndexType k = 1, m = 2; m < verticesCount; k++, m++ ) { + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + const auto v1 = face.template getSubentityIndex< 0 >( k ); + const auto v2 = face.template getSubentityIndex< 0 >( m ); + cellSeed.setCornerId( 0, v0 ); + cellSeed.setCornerId( 1, v1 ); + cellSeed.setCornerId( 2, v2 ); + cellSeed.setCornerId( 3, cellCenterIdx ); + } + } + } + + meshBuilder.build( outMesh ); + return outMesh; +} + +/** + * Tetrahedrons are made by choosing the 0th point of a cell and connecting each triangle of its faces to it. + * Triangles of a face are made by choosing the 0th point of a face and connecting each of its non-adjacent edges to it. + */ +template< typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > +auto +getTetrahedronMesh_v3( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; + using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; + using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; + using LocalIndexType = typename TetrahedronMesh::LocalIndexType; + + TetrahedronMesh outMesh; + MeshBuilder< TetrahedronMesh > meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); + + // outMesh keeps all the points of inMesh + meshBuilder.setPointsCount( inPointsCount ); + for( GlobalIndexType i = 0; i < inPointsCount; i++ ) { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); + } + + // count the number of cells in the outMesh + GlobalIndexType outCellsCount = 0; + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + const auto facesCount = cell.template getSubentitiesCount< 2 >(); + for( LocalIndexType j = 0; j < facesCount; j++ ) { + const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto face = inMesh.template getEntity< 2 >( faceIdx ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + outCellsCount += verticesCount - 2; // there is verticesCount - 2 number of tetrahedrons per face + } + } + meshBuilder.setCellsCount( outCellsCount ); + + // set up cell seeds for the outMesh + for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + const auto v3 = cell.template getSubentityIndex< 0 >( 0 ); // point of the cell connects to triangles of its faces, making tetrahedrons + const auto facesCount = cell.template getSubentitiesCount< 2 >(); + for( LocalIndexType j = 0; j < facesCount; j++ ) { + const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto face = inMesh.template getEntity< 2 >( faceIdx ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + const auto v0 = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles + for( LocalIndexType k = 1, m = 2; m < verticesCount; k++, m++ ) { + const auto v1 = face.template getSubentityIndex< 0 >( k ); + const auto v2 = face.template getSubentityIndex< 0 >( m ); + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + cellSeed.setCornerId( 0, v0 ); + cellSeed.setCornerId( 1, v1 ); + cellSeed.setCornerId( 2, v2 ); + cellSeed.setCornerId( 3, v3 ); + } + } + } + + meshBuilder.build( outMesh ); + return outMesh; +} + +/** + * Tetrahedrons are made by choosing the 0th point of a cell and connecting each triangle of its faces to it. + * Triangles of a face are made by choosing the 0th point of a face and connecting each of its non-adjacent edges to it. + * Additionally, for every tetrahedron, it is checked whether it has non-zero volume. + * If not, given tetrahedron is redundant, thus left out. + */ +template< typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > +auto +getTetrahedronMesh_v4( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; + using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; + using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; + using LocalIndexType = typename TetrahedronMesh::LocalIndexType; + using RealType = typename TetrahedronMesh::RealType; + constexpr RealType precision{ 1e-6 }; + + TetrahedronMesh outMesh; + MeshBuilder< TetrahedronMesh > meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); + + // outMesh keeps all the points of inMesh + meshBuilder.setPointsCount( inPointsCount ); + for( GlobalIndexType i = 0; i < inPointsCount; i++ ) { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); + } + + // count the number of cells in the outMesh + GlobalIndexType outCellsCount = 0; + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + const auto v3Idx = cell.template getSubentityIndex< 0 >( 0 ); // point of the cell connects to triangles of its faces, making tetrahedrons + const auto& v3 = inMesh.getPoint( v3Idx ); + const auto facesCount = cell.template getSubentitiesCount< 2 >(); + for( LocalIndexType j = 0; j < facesCount; j++ ) { + const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto face = inMesh.template getEntity< 2 >( faceIdx ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + const auto v0Idx = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles + const auto& v0 = inMesh.getPoint( v0Idx ); + for( LocalIndexType k = 1, m = 2; m < verticesCount; k++, m++ ) { + const auto v1Idx = face.template getSubentityIndex< 0 >( k ); + const auto& v1 = inMesh.getPoint( v1Idx ); + const auto v2Idx = face.template getSubentityIndex< 0 >( m ); + const auto& v2 = inMesh.getPoint( v2Idx ); + const auto volume = getTetrahedronVolume( v3 - v0, v2 - v0, v1 - v0 ); + if( volume > precision ) { // Leave out redundant tetrahedrons with zero volume + outCellsCount++; + } + } + } + } + meshBuilder.setCellsCount( outCellsCount ); + + // set up cell seeds for the outMesh + for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + const auto v3Idx = cell.template getSubentityIndex< 0 >( 0 ); // point of the cell connects to triangles of its faces, making tetrahedrons + const auto& v3 = inMesh.getPoint( v3Idx ); + const auto facesCount = cell.template getSubentitiesCount< 2 >(); + for( LocalIndexType j = 0; j < facesCount; j++ ) { + const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto face = inMesh.template getEntity< 2 >( faceIdx ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + const auto v0Idx = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles + const auto& v0 = inMesh.getPoint( v0Idx ); + for( LocalIndexType k = 1, m = 2; m < verticesCount; k++, m++ ) { + const auto v1Idx = face.template getSubentityIndex< 0 >( k ); + const auto& v1 = inMesh.getPoint( v1Idx ); + const auto v2Idx = face.template getSubentityIndex< 0 >( m ); + const auto& v2 = inMesh.getPoint( v2Idx ); + const auto volume = getTetrahedronVolume( v3 - v0, v2 - v0, v1 - v0 ); + if( volume > precision ) { // Leave out redundant tetrahedrons with zero volume + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + cellSeed.setCornerId( 0, v0Idx ); + cellSeed.setCornerId( 1, v1Idx ); + cellSeed.setCornerId( 2, v2Idx ); + cellSeed.setCornerId( 3, v3Idx ); + } + } + } + } + + meshBuilder.build( outMesh ); + return outMesh; +} + +/** + * Tetrahedrons are made by choosing the 0th point of a cell and connecting each triangle of its faces to it. + * Triangles of a face are made by choosing the 0th point of a face and connecting each of its non-adjacent edges to it. + * Additionally, for the first tetrahedron of a face, it is checked whether it has non-zero volume. + * If not, all the tetrahedrons of given face are redundant, thus left out. + * It is also assumed that all of the faces are planar. + */ +template< typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > +auto +getTetrahedronMesh_v5( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; + using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; + using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; + using LocalIndexType = typename TetrahedronMesh::LocalIndexType; + using RealType = typename TetrahedronMesh::RealType; + constexpr RealType precision{ 1e-6 }; + + TetrahedronMesh outMesh; + MeshBuilder< TetrahedronMesh > meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); + + // outMesh keeps all the points of inMesh + meshBuilder.setPointsCount( inPointsCount ); + for( GlobalIndexType i = 0; i < inPointsCount; i++ ) { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); + } + + // count the number of cells in the outMesh + GlobalIndexType outCellsCount = 0; + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + const auto v3Idx = cell.template getSubentityIndex< 0 >( 0 ); // point of the cell connects to triangles of its faces, making tetrahedrons + const auto& v3 = inMesh.getPoint( v3Idx ); + const auto facesCount = cell.template getSubentitiesCount< 2 >(); + for( LocalIndexType j = 0; j < facesCount; j++ ) { + const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto face = inMesh.template getEntity< 2 >( faceIdx ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + const auto v0Idx = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles + const auto& v0 = inMesh.getPoint( v0Idx ); + const auto& v1 = inMesh.getPoint( face.template getSubentityIndex< 0 >( 1 ) ); + const auto& v2 = inMesh.getPoint( face.template getSubentityIndex< 0 >( 2 ) ); + const auto volume = getTetrahedronVolume( v3 - v0, v2 - v0, v1 - v0 ); + if( volume > precision ) { // Leave out redundant faces with zero volume tetrahedrons (It is expected that faces are planar) + outCellsCount += verticesCount - 2; // there is verticesCount - 2 number of tetrahedrons per face + } + } + } + meshBuilder.setCellsCount( outCellsCount ); + + // set up cell seeds for the outMesh + for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + const auto v3Idx = cell.template getSubentityIndex< 0 >( 0 ); // point of the cell connects to triangles of its faces, making tetrahedrons + const auto& v3 = inMesh.getPoint( v3Idx ); + const auto facesCount = cell.template getSubentitiesCount< 2 >(); + for( LocalIndexType j = 0; j < facesCount; j++ ) { + const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto face = inMesh.template getEntity< 2 >( faceIdx ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + const auto v0Idx = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles + const auto& v0 = inMesh.getPoint( v0Idx ); + const auto& v1 = inMesh.getPoint( face.template getSubentityIndex< 0 >( 1 ) ); + const auto& v2 = inMesh.getPoint( face.template getSubentityIndex< 0 >( 2 ) ); + const auto volume = getTetrahedronVolume( v3 - v0, v2 - v0, v1 - v0 ); + if( volume <= precision ) // Leave out redundant faces with zero volume tetrahedrons (It is expected that faces are planar) + continue; + for( LocalIndexType k = 1, m = 2; m < verticesCount; k++, m++ ) { + const auto v1Idx = face.template getSubentityIndex< 0 >( k ); + const auto v2Idx = face.template getSubentityIndex< 0 >( m ); + auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); + cellSeed.setCornerId( 0, v0Idx ); + cellSeed.setCornerId( 1, v1Idx ); + cellSeed.setCornerId( 2, v2Idx ); + cellSeed.setCornerId( 3, v3Idx ); + } + } + } + + meshBuilder.build( outMesh ); + return outMesh; +} + +template< GetTetrahedronMeshVersion version, + typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > +auto +getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + switch( version ) + { + case GetTetrahedronMeshVersion::V1: return getTetrahedronMesh_v1( inMesh ); + case GetTetrahedronMeshVersion::V2: return getTetrahedronMesh_v2( inMesh ); + case GetTetrahedronMeshVersion::V3: return getTetrahedronMesh_v3( inMesh ); + case GetTetrahedronMeshVersion::V4: return getTetrahedronMesh_v4( inMesh ); + case GetTetrahedronMeshVersion::V5: return getTetrahedronMesh_v5( inMesh ); + } +} + +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Geometry/getEntityMeasure.h b/src/TNL/Meshes/Geometry/getEntityMeasure.h index 6debfbec6..649f90877 100644 --- a/src/TNL/Meshes/Geometry/getEntityMeasure.h +++ b/src/TNL/Meshes/Geometry/getEntityMeasure.h @@ -189,6 +189,10 @@ getPolygon2DArea( const Mesh< MeshConfig, Device > & mesh, { // 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; @@ -315,7 +319,7 @@ getEntityMeasure( const Mesh< MeshConfig, Device > & mesh, } // Polyhedron -template< typename MeshConfig, +/*template< typename MeshConfig, typename Device > __cuda_callable__ typename MeshConfig::RealType @@ -347,6 +351,32 @@ getEntityMeasure( const Mesh< MeshConfig, Device > & mesh, } } 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; } } // namespace Meshes diff --git a/src/UnitTests/Meshes/MeshGeometryTest.h b/src/UnitTests/Meshes/MeshGeometryTest.h index 7766e6301..6f1f8dda8 100644 --- a/src/UnitTests/Meshes/MeshGeometryTest.h +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -18,6 +18,9 @@ #include #include +#include + +#include namespace MeshGeometryTest { @@ -452,6 +455,418 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) 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.setPointsCount( 16 ); + 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.setCellsCount( 7 ); + + // 1 0 3 2 4 5 + meshBuilder.getCellSeed( 0 ).setCornersCount( 6 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ) ); + + // Write original mesh + { + using VTKWriter = Meshes::Writers::VTKWriter< decltype( mesh ) >; + std::ofstream file( "polygonTest_orig.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( mesh ); + } + + // Write decomposed mesh using 1st version + { + auto triangleMesh = getDecomposedMesh< GetTriangleMeshVersion::V1 >( mesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( triangleMesh ) >; + std::ofstream file( "polygonTest_v1.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( triangleMesh ); + } + + // Write decomposed mesh using 2nd version + { + auto triangleMesh = getDecomposedMesh< GetTriangleMeshVersion::V2 >( mesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( triangleMesh ) >; + std::ofstream file( "polygonTest_v2.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( triangleMesh ); + } +} + +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.setPointsCount( 22 ); + 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: indeces refer to the points + */ + + meshBuilder.setFacesCount( 16 ); + + // 0 1 2 3 4 + meshBuilder.getFaceSeed( 0 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 6 ); + 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 ).setCornersCount( 3 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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: indeces refer to the faces + */ + + meshBuilder.setCellsCount( 2 ); + + // 0 1 2 3 4 5 6 7 8 + meshBuilder.getCellSeed( 0 ).setCornersCount( 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 ); + + // 9 10 11 12 13 5 14 15 + meshBuilder.getCellSeed( 1 ).setCornersCount( 8 ); + 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 ) ); + + // Write decomposed mesh using 1st version + { + auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V1 >( mesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; + std::ofstream file( "polyhedronTest_v1.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( tetrahedronMesh ); + } + + // Write decomposed mesh using 2nd version + { + auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V2 >( mesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; + std::ofstream file( "polyhedronTest_v2.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( tetrahedronMesh ); + } + + // Write decomposed mesh using 3rd version + { + auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V3 >( mesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; + std::ofstream file( "polyhedronTest_v3.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( tetrahedronMesh ); + } + + // Write decomposed mesh using 4th version + { + auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V4 >( mesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; + std::ofstream file( "polyhedronTest_v4.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( tetrahedronMesh ); + } + + // Write decomposed mesh using 5th version + { + auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V5 >( mesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; + std::ofstream file( "polyhedronTest_v5.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( tetrahedronMesh ); + } +} + } // namespace MeshTest #endif -- GitLab From f1389ef879658920c07f4866d7591eeebcf6267f Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Wed, 23 Jun 2021 16:53:02 +0200 Subject: [PATCH 16/42] Meshes/Geometry: added function getPlanarMesh + refactoring - added function getPlanarMesh for correcting non-planar polygons in 3D polygon and polyhedral meshes - added unit tests for getPlanarMesh function - refactored getDecomposedMesh specialization for polygons by creating PolygonDecomposer struct to reuse decomposing logic in getPlanarMesh function - other minor refactoring in Meshes/MeshGeometryTest.h --- src/TNL/Meshes/Geometry/PolygonDecomposer.h | 123 +++++ src/TNL/Meshes/Geometry/getDecomposedMesh.h | 147 +----- src/TNL/Meshes/Geometry/getPlanarMesh.h | 193 +++++++ src/UnitTests/Meshes/CMakeLists.txt | 2 +- src/UnitTests/Meshes/MeshGeometryTest.h | 532 ++++++++++++++++---- 5 files changed, 775 insertions(+), 222 deletions(-) create mode 100644 src/TNL/Meshes/Geometry/PolygonDecomposer.h create mode 100644 src/TNL/Meshes/Geometry/getPlanarMesh.h diff --git a/src/TNL/Meshes/Geometry/PolygonDecomposer.h b/src/TNL/Meshes/Geometry/PolygonDecomposer.h new file mode 100644 index 000000000..177906df9 --- /dev/null +++ b/src/TNL/Meshes/Geometry/PolygonDecomposer.h @@ -0,0 +1,123 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace TNL { +namespace Meshes { + +enum class PolygonDecomposerVersion +{ + ConnectEdgesToCentroid, ConnectEdgesToPoint +}; + +template< typename MeshConfig, PolygonDecomposerVersion > +struct PolygonDecomposer; + +template< typename MeshConfig > +struct PolygonDecomposer< MeshConfig, PolygonDecomposerVersion::ConnectEdgesToCentroid > +{ + using Device = typename Devices::Host; + using Topology = typename Topologies::Polygon; + using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + + static GlobalIndexType getExtraPointsCount( const MeshEntityType & entity ) + { + return 1; + } + + static GlobalIndexType getEntitiesCount( const MeshEntityType & entity ) + { + const auto pointsCount = entity.template getSubentitiesCount< 0 >(); + return ( pointsCount == 3 ) ? 1 : pointsCount; // polygon is decomposed only if it has more than 3 vertices + } + + template< typename MeshType, typename EntitySeedGetterType > + static void decompose( MeshBuilder< MeshType > & meshBuilder, + EntitySeedGetterType entitySeedGetter, + GlobalIndexType & pointsCount, + GlobalIndexType & entitiesCount, + const MeshEntityType & entity ) + { + const auto verticesCount = entity.template getSubentitiesCount< 0 >(); + if( verticesCount == 3 ) { // polygon is not decomposed as it's already a triangle + auto & entitySeed = entitySeedGetter( entitiesCount++ ); + entitySeed.setCornersCount( 3 ); + entitySeed.setCornerId( 0, entity.template getSubentityIndex< 0 >( 0 ) ); + entitySeed.setCornerId( 1, entity.template getSubentityIndex< 0 >( 1 ) ); + entitySeed.setCornerId( 2, entity.template getSubentityIndex< 0 >( 2 ) ); + } + else { // polygon is decomposed as it has got more than 3 vertices + // add centroid of entity to points + const auto entityCenter = getEntityCenter( entity.getMesh(), entity ); + const auto entityCenterIdx = pointsCount++; + meshBuilder.setPoint( entityCenterIdx, entityCenter ); + // decompose polygon into triangles by connecting each edge to the centroid + for( LocalIndexType j = 0, k = 1; k < verticesCount; j++, k++ ) { + auto & entitySeed = entitySeedGetter( entitiesCount++ ); + entitySeed.setCornersCount( 3 ); + entitySeed.setCornerId( 0, entity.template getSubentityIndex< 0 >( j ) ); + entitySeed.setCornerId( 1, entity.template getSubentityIndex< 0 >( k ) ); + entitySeed.setCornerId( 2, entityCenterIdx ); + } + { // wrap around term + auto & entitySeed = entitySeedGetter( entitiesCount++ ); + entitySeed.setCornersCount( 3 ); + entitySeed.setCornerId( 0, entity.template getSubentityIndex< 0 >( verticesCount - 1 ) ); + entitySeed.setCornerId( 1, entity.template getSubentityIndex< 0 >( 0 ) ); + entitySeed.setCornerId( 2, entityCenterIdx ); + } + } + } +}; + +template< typename MeshConfig > +struct PolygonDecomposer< MeshConfig, PolygonDecomposerVersion::ConnectEdgesToPoint > +{ + using Device = typename Devices::Host; + using Topology = typename Topologies::Polygon; + using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + + static GlobalIndexType getExtraPointsCount( const MeshEntityType & entity ) + { + return 0; // No extra points are added + } + + static GlobalIndexType getEntitiesCount( const MeshEntityType & entity ) + { + const auto pointsCount = entity.template getSubentitiesCount< 0 >(); + return pointsCount - 2; // there is a new triangle for every non-adjacent edge to the 0th point + } + + template< typename MeshType, typename EntitySeedGetterType > + static void decompose( MeshBuilder< MeshType > & meshBuilder, + EntitySeedGetterType entitySeedGetter, + GlobalIndexType & pointsCount, + GlobalIndexType & entitiesCount, + const MeshEntityType & entity ) + { + // 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++ ) { + auto & entitySeed = entitySeedGetter( entitiesCount++ ); + const auto v1 = entity.template getSubentityIndex< 0 >( j ); + const auto v2 = entity.template getSubentityIndex< 0 >( k ); + entitySeed.setCornersCount( 3 ); + entitySeed.setCornerId( 0, v0 ); + entitySeed.setCornerId( 1, v1 ); + entitySeed.setCornerId( 2, v2 ); + } + } +}; + +} // namespace Meshes +} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h index 4a97425e0..7f477b8df 100644 --- a/src/TNL/Meshes/Geometry/getDecomposedMesh.h +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -1,22 +1,19 @@ #pragma once -#include #include #include -#include -#include +#include #include #include #include #include -#include #include #include +#include namespace TNL { namespace Meshes { - // Polygon Mesh template< typename ParentConfig > struct TriangleConfig: public ParentConfig @@ -24,155 +21,59 @@ struct TriangleConfig: public ParentConfig using CellTopology = Topologies::Triangle; }; -enum class GetTriangleMeshVersion -{ - V1, V2 -}; - -/** - * Triangles are made by connecting each edge to the centroid of cell. - */ -template< typename MeshConfig, +template< PolygonDecomposerVersion version, + typename MeshConfig, std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true > auto -getTriangleMesh_v1( const Mesh< MeshConfig, Devices::Host > & inMesh ) +getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) { using TriangleMeshConfig = TriangleConfig< MeshConfig >; using TriangleMesh = Mesh< TriangleMeshConfig, Devices::Host >; + using MeshBuilder = MeshBuilder< TriangleMesh >; using GlobalIndexType = typename TriangleMesh::GlobalIndexType; using LocalIndexType = typename TriangleMesh::LocalIndexType; - + using PolygonDecomposer = PolygonDecomposer< MeshConfig, version >; + TriangleMesh outMesh; - MeshBuilder< TriangleMesh > meshBuilder; + MeshBuilder meshBuilder; const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 2 >(); - // find the number of points and cells in the outMesh + // Find the number of points and cells in the outMesh GlobalIndexType outPointsCount = inPointsCount; GlobalIndexType outCellsCount = 0; for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 2 >( i ); - const auto verticesCount = cell.template getSubentitiesCount< 0 >(); - if( verticesCount == 3 ) { // cell is not decomposed as it's already a triangle - outCellsCount++; // cell is just copied - } - else { // cell is decomposed as it has got more than 3 vertices - outPointsCount++; // each decomposed cell has 1 new center point - outCellsCount += verticesCount; // cell is decomposed into verticesCount number of triangles - } + outPointsCount += PolygonDecomposer::getExtraPointsCount( cell ); + outCellsCount += PolygonDecomposer::getEntitiesCount( cell ); } meshBuilder.setPointsCount( outPointsCount ); meshBuilder.setCellsCount( outCellsCount ); - // copy the points from inMesh to outMesh - GlobalIndexType pointSetIdx = 0; - for( ; pointSetIdx < inPointsCount; pointSetIdx++ ) { - meshBuilder.setPoint( pointSetIdx, inMesh.getPoint( pointSetIdx ) ); + // Copy the points from inMesh to outMesh + GlobalIndexType setPointsCount = 0; + for( ; setPointsCount < inPointsCount; setPointsCount++ ) { + meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); } - for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { + // Decompose each cell into triangles + auto cellSeedGetter = [&] ( const GlobalIndexType i ) -> auto& { return meshBuilder.getCellSeed( i ); }; + for( GlobalIndexType i = 0, setCellsCount = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 2 >( i ); - const auto verticesCount = cell.template getSubentitiesCount< 0 >(); - if( verticesCount == 3 ) { // cell is not decomposed as it's already a triangle - // copy cell - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - cellSeed.setCornerId( 0, cell.template getSubentityIndex< 0 >( 0 ) ); - cellSeed.setCornerId( 1, cell.template getSubentityIndex< 0 >( 1 ) ); - cellSeed.setCornerId( 2, cell.template getSubentityIndex< 0 >( 2 ) ); - } - else { // cell is decomposed as it has got more than 3 vertices - // add centroid of cell to outMesh - const auto cellCenter = getEntityCenter( inMesh, cell ); - const auto cellCenterIdx = pointSetIdx++; - meshBuilder.setPoint( cellCenterIdx, cellCenter ); - // decompose cell into triangles by connecting each edge to the centroid - for( LocalIndexType j = 0, k = 1; k < verticesCount; j++, k++ ) { - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - cellSeed.setCornerId( 0, cell.template getSubentityIndex< 0 >( j ) ); - cellSeed.setCornerId( 1, cell.template getSubentityIndex< 0 >( k ) ); - cellSeed.setCornerId( 2, cellCenterIdx ); - } - { // wrap around term - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - cellSeed.setCornerId( 0, cell.template getSubentityIndex< 0 >( verticesCount - 1 ) ); - cellSeed.setCornerId( 1, cell.template getSubentityIndex< 0 >( 0 ) ); - cellSeed.setCornerId( 2, cellCenterIdx ); - } - } + PolygonDecomposer::decompose( meshBuilder, + cellSeedGetter, + setPointsCount, + setCellsCount, + cell ); } meshBuilder.build( outMesh ); return outMesh; } -/** - * Triangles are made by choosing the 0th point of cell and connecting each non-adjacent edge to it. - */ -template< typename MeshConfig, - std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true > -auto -getTriangleMesh_v2( const Mesh< MeshConfig, Devices::Host > & inMesh ) -{ - using TriangleMeshConfig = TriangleConfig< MeshConfig >; - using TriangleMesh = Mesh< TriangleMeshConfig, Devices::Host >; - using GlobalIndexType = typename TriangleMesh::GlobalIndexType; - using LocalIndexType = typename TriangleMesh::LocalIndexType; - - TriangleMesh outMesh; - MeshBuilder< TriangleMesh > meshBuilder; - - const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); - const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 2 >(); - - // outMesh keeps all the points of inMesh - meshBuilder.setPointsCount( inPointsCount ); - for( GlobalIndexType i = 0; i < inPointsCount; i++ ) { - meshBuilder.setPoint( i, inMesh.getPoint( i ) ); - } - - // find the number of cells in the outMesh - GlobalIndexType outCellsCount = 0; - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 2 >( i ); - const auto verticesCount = cell.template getSubentitiesCount< 0 >(); - outCellsCount += verticesCount - 2; - } - meshBuilder.setCellsCount( outCellsCount ); - - for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 2 >( i ); - const auto verticesCount = cell.template getSubentitiesCount< 0 >(); - const auto v0 = cell.template getSubentityIndex< 0 >( 0 ); - for( LocalIndexType j = 1, k = 2; k < verticesCount; j++, k++ ) { - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - const auto v1 = cell.template getSubentityIndex< 0 >( j ); - const auto v2 = cell.template getSubentityIndex< 0 >( k ); - cellSeed.setCornerId( 0, v0 ); - cellSeed.setCornerId( 1, v1 ); - cellSeed.setCornerId( 2, v2 ); - } - } - - meshBuilder.build( outMesh ); - return outMesh; -} - -template< GetTriangleMeshVersion version, - typename MeshConfig, - std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true > -auto -getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) -{ - switch( version ) - { - case GetTriangleMeshVersion::V1: return getTriangleMesh_v1( inMesh ); - case GetTriangleMeshVersion::V2: return getTriangleMesh_v2( inMesh ); - } -} - // Polyhedral Mesh template< typename ParentConfig > struct TetrahedronConfig: public ParentConfig diff --git a/src/TNL/Meshes/Geometry/getPlanarMesh.h b/src/TNL/Meshes/Geometry/getPlanarMesh.h new file mode 100644 index 000000000..f80cd7c43 --- /dev/null +++ b/src/TNL/Meshes/Geometry/getPlanarMesh.h @@ -0,0 +1,193 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace TNL { +namespace Meshes { + +// 3D Polygon Mesh +template< PolygonDecomposerVersion version, + 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 > +Mesh< MeshConfig, Devices::Host > +getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + using PolygonMesh = Mesh< MeshConfig, Devices::Host >; + using MeshBuilder = MeshBuilder< PolygonMesh >; + using GlobalIndexType = typename PolygonMesh::GlobalIndexType; + using LocalIndexType = typename PolygonMesh::LocalIndexType; + using RealType = typename PolygonMesh::RealType; + using PolygonDecomposer = PolygonDecomposer< MeshConfig, version >; + + constexpr RealType precision{ 1e-6 }; + + PolygonMesh outMesh; + MeshBuilder meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 2 >(); + + // find the number of points and cells in the outMesh + GlobalIndexType outPointsCount = inPointsCount; + GlobalIndexType outCellsCount = 0; + + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 2 >( i ); + if( isPlanar( inMesh, cell, precision ) ) { // Cell is not decomposed + outCellsCount++; + } + else { // Cell is decomposed + outPointsCount += PolygonDecomposer::getExtraPointsCount( cell ); + outCellsCount += PolygonDecomposer::getEntitiesCount( cell ); + } + } + + meshBuilder.setPointsCount( outPointsCount ); + meshBuilder.setCellsCount( outCellsCount ); + + // copy the points from inMesh to outMesh + GlobalIndexType setPointsCount = 0; + for( ; setPointsCount < inPointsCount; setPointsCount++ ) { + meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); + } + + auto cellSeedGetter = [&] ( const GlobalIndexType i ) -> auto& { return meshBuilder.getCellSeed( i ); }; + for( GlobalIndexType i = 0, setCellsCount = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 2 >( i ); + if( isPlanar( inMesh, cell, precision ) ) { // Copy planar cells + auto & cellSeed = meshBuilder.getCellSeed( setCellsCount++ ); + const auto verticesCount = cell.template getSubentitiesCount< 0 >(); + cellSeed.setCornersCount( verticesCount ); + for( LocalIndexType j = 0; j < verticesCount; j++ ) { + cellSeed.setCornerId( j, cell.template getSubentityIndex< 0 >( j ) ); + } + } + else { // decompose non-planar cells + PolygonDecomposer::decompose( meshBuilder, + cellSeedGetter, + setPointsCount, + setCellsCount, + cell ); + } + } + + meshBuilder.build( outMesh ); + return outMesh; +} + +// Polyhedral Mesh +template< PolygonDecomposerVersion version, + typename MeshConfig, + std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > +Mesh< MeshConfig, Devices::Host > +getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) +{ + using PolyhedronMesh = Mesh< MeshConfig, Devices::Host >; + using GlobalIndexType = typename PolyhedronMesh::GlobalIndexType; + using LocalIndexType = typename PolyhedronMesh::LocalIndexType; + using RealType = typename PolyhedronMesh::RealType; + using FaceMapArray = Containers::Array< std::pair< GlobalIndexType, GlobalIndexType >, Devices::Host, GlobalIndexType >; + using PolygonDecomposer = PolygonDecomposer< MeshConfig, version >; + + constexpr RealType precision{ 1e-6 }; + + PolyhedronMesh outMesh; + MeshBuilder< PolyhedronMesh > meshBuilder; + + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); + const GlobalIndexType inFacesCount = inMesh.template getEntitiesCount< 2 >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); + + FaceMapArray faceMap( inFacesCount ); + + // find the number of points and faces in the outMesh + GlobalIndexType outPointsCount = inPointsCount; + GlobalIndexType outFacesCount = 0; + for( GlobalIndexType i = 0; i < inFacesCount; i++ ) { + const auto face = inMesh.template getEntity< 2 >( i ); + if( isPlanar( inMesh, face, precision ) ) { // + const auto startFaceIdx = outFacesCount; + const auto endFaceIdx = ++outFacesCount; + faceMap[ i ] = { startFaceIdx, endFaceIdx }; + } + else { + outPointsCount += PolygonDecomposer::getExtraPointsCount( face ); + const auto startFaceIdx = outFacesCount; + outFacesCount += PolygonDecomposer::getEntitiesCount( face ); + const auto endFaceIdx = outFacesCount; + faceMap[ i ] = { startFaceIdx, endFaceIdx }; + } + } + + meshBuilder.setPointsCount( outPointsCount ); + meshBuilder.setFacesCount( outFacesCount ); + meshBuilder.setCellsCount( inCellsCount ); // The number of cells stays the same + + // copy the points from inMesh to outMesh + GlobalIndexType setPointsCount = 0; + for( ; setPointsCount < inPointsCount; setPointsCount++ ) { + meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); + } + + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + const LocalIndexType cellFacesCount = cell.template getSubentitiesCount< 2 >(); + + // Find the number of faces in the output cell + LocalIndexType cellSeedFacesCount = 0; + for( LocalIndexType j = 0; j < cellFacesCount; j++ ) { + const GlobalIndexType faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto & faceMapping = faceMap[ faceIdx ]; + cellSeedFacesCount += faceMapping.second - faceMapping.first; + } + + // Set up the cell seed + auto & cellSeed = meshBuilder.getCellSeed( i ); + cellSeed.setCornersCount( cellSeedFacesCount ); + for( LocalIndexType j = 0, faceSetIdx = 0; j < cellFacesCount; j++ ) { + const GlobalIndexType faceIdx = cell.template getSubentityIndex< 2 >( j ); + const auto & faceMapping = faceMap[ faceIdx ]; + for( GlobalIndexType k = faceMapping.first; k < faceMapping.second; k++ ) { + cellSeed.setCornerId( faceSetIdx++, k ); + } + } + } + + auto faceSeedGetter = [&] ( const GlobalIndexType i ) -> auto& { return meshBuilder.getFaceSeed( i ); }; + for( GlobalIndexType i = 0, setFacesCount = 0; i < inFacesCount; i++ ) { + const auto face = inMesh.template getEntity< 2 >( i ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + const auto & faceMapping = faceMap[ i ]; + const bool isPlanarRes = ( faceMapping.second - faceMapping.first ) == 1; // face was planar if face maps only onto 1 face + if( isPlanarRes ) { // Copy planar faces + auto & faceSeed = meshBuilder.getFaceSeed( setFacesCount++ ); + faceSeed.setCornersCount( verticesCount ); + for( LocalIndexType j = 0; j < verticesCount; j++ ) { + faceSeed.setCornerId( j, face.template getSubentityIndex< 0 >( j ) ); + } + } + else { // decompose non-planar cells + PolygonDecomposer::decompose( meshBuilder, + faceSeedGetter, + setPointsCount, + setFacesCount, + face ); + } + } + + faceMap.reset(); + meshBuilder.build( outMesh ); + return outMesh; +} + +} // namespace Meshes +} // namespace TNL diff --git a/src/UnitTests/Meshes/CMakeLists.txt b/src/UnitTests/Meshes/CMakeLists.txt index b6675b366..7ffed3066 100644 --- a/src/UnitTests/Meshes/CMakeLists.txt +++ b/src/UnitTests/Meshes/CMakeLists.txt @@ -23,7 +23,7 @@ if( ${BUILD_CUDA} AND ${CUDA_VERSION_MAJOR} GREATER_EQUAL 9 ) target_link_options( MeshOrderingTest PRIVATE ${TESTS_LINKER_FLAGS} ) CUDA_ADD_EXECUTABLE( MeshGeometryTest MeshGeometryTest.cu - OPTIONS ${CXX_TESTS_FLAGS} ) + OPTIONS ${CUDA_TESTS_FLAGS} ) TARGET_LINK_LIBRARIES( MeshGeometryTest ${TESTS_LIBRARIES} ) target_link_options( MeshGeometryTest PRIVATE ${TESTS_LINKER_FLAGS} ) else() diff --git a/src/UnitTests/Meshes/MeshGeometryTest.h b/src/UnitTests/Meshes/MeshGeometryTest.h index 6f1f8dda8..2630e1e65 100644 --- a/src/UnitTests/Meshes/MeshGeometryTest.h +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -34,9 +35,10 @@ public: static constexpr bool superentityStorage( int entityDimension, int superentityDimension ) { return true; } }; -class TestPolygon3DMeshConfig : public DefaultConfig< Topologies::Polyhedron > +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; } }; @@ -105,9 +107,9 @@ TEST( MeshGeometryTest, Polygon2DAreaTest ) TEST( MeshGeometryTest, Polygon3DAreaTest ) { - using PolyhedronTestMesh = Mesh< TestPolygon3DMeshConfig >; - using PolyhedronMeshEntityType = MeshEntity< TestPolygon3DMeshConfig, Devices::Host, Topologies::Polyhedron >; - using VertexMeshEntityType = typename PolyhedronMeshEntityType::SubentityTraits< 0 >::SubentityType; + 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. @@ -126,8 +128,8 @@ TEST( MeshGeometryTest, Polygon3DAreaTest ) point3( 5.86983, 8.12036, 2.56999 ), point4( 2.11438, 6.71405, 3.52860 ); - PolyhedronTestMesh mesh; - MeshBuilder< PolyhedronTestMesh > meshBuilder; + PolygonTestMesh mesh; + MeshBuilder< PolygonTestMesh > meshBuilder; meshBuilder.setPointsCount( 5 ); meshBuilder.setPoint( 0, point0 ); @@ -136,17 +138,13 @@ TEST( MeshGeometryTest, Polygon3DAreaTest ) meshBuilder.setPoint( 3, point3 ); meshBuilder.setPoint( 4, point4 ); - meshBuilder.setFacesCount( 1 ); - meshBuilder.getFaceSeed( 0 ).setCornersCount( 5 ); - 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 ); - meshBuilder.setCellsCount( 1 ); - meshBuilder.getCellSeed( 0 ).setCornersCount( 1 ); + meshBuilder.getCellSeed( 0 ).setCornersCount( 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 ) ); @@ -340,13 +338,13 @@ TEST( MeshGeometryTest, PolyhedronAreaTest ) TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) { - using PolyhedronTestMesh = Mesh< TestPolygon3DMeshConfig >; - using PolyhedronMeshEntityType = MeshEntity< TestPolygon3DMeshConfig, Devices::Host, Topologies::Polyhedron >; - using VertexMeshEntityType = typename PolyhedronMeshEntityType::SubentityTraits< 0 >::SubentityType; + 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 PolyhedronTestMesh::RealType; + using RealType = typename PolygonTestMesh::RealType; - constexpr RealType offset[] = { 0.100, 0.125, 0.150 }; + const PointType offset( 0.100, 0.125, 0.150 ); // Set up 1 planar and 5 non-planar non-convex 3D polygons. @@ -365,14 +363,14 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) point4( 2.11438, 6.71405, 3.52860 ); // Previous 5 points deviated by offset: - PointType point0_( point0[0] + offset[0], point0[1] + offset[1], point0[2] + offset[2] ), - point1_( point1[0] + offset[0], point1[1] + offset[1], point1[2] + offset[2] ), - point2_( point2[0] + offset[0], point2[1] + offset[1], point2[2] + offset[2] ), - point3_( point3[0] + offset[0], point3[1] + offset[1], point3[2] + offset[2] ), - point4_( point4[0] + offset[0], point4[1] + offset[1], point4[2] + offset[2] ); + PointType point0_( point0 + offset ), + point1_( point1 + offset ), + point2_( point2 + offset ), + point3_( point3 + offset ), + point4_( point4 + offset ); - PolyhedronTestMesh mesh; - MeshBuilder< PolyhedronTestMesh > meshBuilder; + PolygonTestMesh mesh; + MeshBuilder< PolygonTestMesh > meshBuilder; meshBuilder.setPointsCount( 10 ); meshBuilder.setPoint( 0, point0 ); @@ -386,64 +384,55 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) meshBuilder.setPoint( 8, point3_ ); meshBuilder.setPoint( 9, point4_ ); - meshBuilder.setFacesCount( 6 ); - - // Planar face with non-deviated points - meshBuilder.getFaceSeed( 0 ).setCornersCount( 5 ); - 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 ); - - // Non-Planar face with 0th point deviated - meshBuilder.getFaceSeed( 1 ).setCornersCount( 5 ); - meshBuilder.getFaceSeed( 1 ).setCornerId( 0, 5 ); - meshBuilder.getFaceSeed( 1 ).setCornerId( 1, 1 ); - meshBuilder.getFaceSeed( 1 ).setCornerId( 2, 2 ); - meshBuilder.getFaceSeed( 1 ).setCornerId( 3, 3 ); - meshBuilder.getFaceSeed( 1 ).setCornerId( 4, 4 ); - - // Non-Planar face with 1th point deviated - meshBuilder.getFaceSeed( 2 ).setCornersCount( 5 ); - meshBuilder.getFaceSeed( 2 ).setCornerId( 0, 0 ); - meshBuilder.getFaceSeed( 2 ).setCornerId( 1, 6 ); - meshBuilder.getFaceSeed( 2 ).setCornerId( 2, 2 ); - meshBuilder.getFaceSeed( 2 ).setCornerId( 3, 3 ); - meshBuilder.getFaceSeed( 2 ).setCornerId( 4, 4 ); + meshBuilder.setCellsCount( 6 ); - // Non-Planar face with 2th point deviated - meshBuilder.getFaceSeed( 3 ).setCornersCount( 5 ); - meshBuilder.getFaceSeed( 3 ).setCornerId( 0, 0 ); - meshBuilder.getFaceSeed( 3 ).setCornerId( 1, 1 ); - meshBuilder.getFaceSeed( 3 ).setCornerId( 2, 7 ); - meshBuilder.getFaceSeed( 3 ).setCornerId( 3, 3 ); - meshBuilder.getFaceSeed( 3 ).setCornerId( 4, 4 ); - - // Non-Planar face with 3th point deviated - meshBuilder.getFaceSeed( 4 ).setCornersCount( 5 ); - meshBuilder.getFaceSeed( 4 ).setCornerId( 0, 0 ); - meshBuilder.getFaceSeed( 4 ).setCornerId( 1, 1 ); - meshBuilder.getFaceSeed( 4 ).setCornerId( 2, 2 ); - meshBuilder.getFaceSeed( 4 ).setCornerId( 3, 8 ); - meshBuilder.getFaceSeed( 4 ).setCornerId( 4, 4 ); - - // Non-Planar face with 4th point deviated - meshBuilder.getFaceSeed( 5 ).setCornersCount( 5 ); - meshBuilder.getFaceSeed( 5 ).setCornerId( 0, 0 ); - meshBuilder.getFaceSeed( 5 ).setCornerId( 1, 1 ); - meshBuilder.getFaceSeed( 5 ).setCornerId( 2, 2 ); - meshBuilder.getFaceSeed( 5 ).setCornerId( 3, 3 ); - meshBuilder.getFaceSeed( 5 ).setCornerId( 4, 9 ); - - meshBuilder.setCellsCount( 1 ); - meshBuilder.getCellSeed( 0 ).setCornersCount( 6 ); + // Planar cell with non-deviated points + meshBuilder.getCellSeed( 0 ).setCornersCount( 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 ); - meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); + + // Non-Planar cell with 0th point deviated + meshBuilder.getCellSeed( 1 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ) ); @@ -496,7 +485,7 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) */ meshBuilder.setCellsCount( 7 ); - + // 1 0 3 2 4 5 meshBuilder.getCellSeed( 0 ).setCornersCount( 6 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 1 ); @@ -543,7 +532,7 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) 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 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 6 ).setCornerId( 0, 10 ); @@ -551,31 +540,31 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) meshBuilder.getCellSeed( 6 ).setCornerId( 2, 4 ); meshBuilder.getCellSeed( 6 ).setCornerId( 3, 13 ); meshBuilder.getCellSeed( 6 ).setCornerId( 4, 15 ); - + ASSERT_TRUE( meshBuilder.build( mesh ) ); // Write original mesh { using VTKWriter = Meshes::Writers::VTKWriter< decltype( mesh ) >; - std::ofstream file( "polygonTest_orig.vtk" ); + std::ofstream file( "polygon_decompositionTest_orig.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( mesh ); } // Write decomposed mesh using 1st version { - auto triangleMesh = getDecomposedMesh< GetTriangleMeshVersion::V1 >( mesh ); + auto triangleMesh = getDecomposedMesh< PolygonDecomposerVersion::ConnectEdgesToCentroid >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( triangleMesh ) >; - std::ofstream file( "polygonTest_v1.vtk" ); + std::ofstream file( "polygon_decompositionTest_v1.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( triangleMesh ); } // Write decomposed mesh using 2nd version { - auto triangleMesh = getDecomposedMesh< GetTriangleMeshVersion::V2 >( mesh ); + auto triangleMesh = getDecomposedMesh< PolygonDecomposerVersion::ConnectEdgesToPoint >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( triangleMesh ) >; - std::ofstream file( "polygonTest_v2.vtk" ); + std::ofstream file( "polygon_decompositionTest_v2.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( triangleMesh ); } @@ -657,7 +646,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) * 21 19 18 20 * 21 20 11 12 * 12 8 16 19 21 - * + * * NOTE: indeces refer to the points */ @@ -670,7 +659,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) 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 ).setCornersCount( 4 ); meshBuilder.getFaceSeed( 1 ).setCornerId( 0, 4 ); @@ -685,7 +674,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) 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 ).setCornersCount( 4 ); meshBuilder.getFaceSeed( 3 ).setCornerId( 0, 9 ); @@ -790,7 +779,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) * * 0 1 2 3 4 5 6 7 8 * 9 10 11 12 13 5 14 15 - * + * * NOTE: indeces refer to the faces */ @@ -820,21 +809,21 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getCellSeed( 1 ).setCornerId( 7, 15 ); ASSERT_TRUE( meshBuilder.build( mesh ) ); - + // Write decomposed mesh using 1st version { auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V1 >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedronTest_v1.vtk" ); + std::ofstream file( "polyhedron_decompositionTest_v1.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } - + // Write decomposed mesh using 2nd version { auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V2 >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedronTest_v2.vtk" ); + std::ofstream file( "polyhedron_decompositionTest_v2.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } @@ -843,7 +832,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) { auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V3 >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedronTest_v3.vtk" ); + std::ofstream file( "polyhedron_decompositionTest_v3.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } @@ -852,7 +841,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) { auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V4 >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedronTest_v4.vtk" ); + std::ofstream file( "polyhedron_decompositionTest_v4.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } @@ -861,7 +850,354 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) { auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V5 >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedronTest_v5.vtk" ); + std::ofstream file( "polyhedron_decompositionTest_v5.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( tetrahedronMesh ); + } +} + +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.setPointsCount( 6 ); + 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.setCellsCount( 2 ); + + // Planar cell + meshBuilder.getCellSeed( 0 ).setCornersCount( 4 ); + 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 ).setCornersCount( 4 ); + 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 ); + } + + // Write decomposed mesh using 1st version + { + auto planarMesh = getPlanarMesh< PolygonDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( planarMesh ) >; + std::ofstream file( "polygon_planarTest_v1.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( planarMesh ); + } + + // Write decomposed mesh using 2nd version + { + auto planarMesh = getPlanarMesh< PolygonDecomposerVersion::ConnectEdgesToPoint >( mesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( planarMesh ) >; + std::ofstream file( "polygon_planarTest_v2.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( planarMesh ); + } +} + +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.setPointsCount( 22 ); + 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: indeces refer to the points + */ + + meshBuilder.setFacesCount( 16 ); + + // 0 1 2 3 4 + meshBuilder.getFaceSeed( 0 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 5 ); + 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 ).setCornersCount( 6 ); + 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 ).setCornersCount( 3 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 4 ); + 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 ).setCornersCount( 5 ); + 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: indeces refer to the faces + */ + + meshBuilder.setCellsCount( 2 ); + + // 0 1 2 3 4 5 6 7 8 + meshBuilder.getCellSeed( 0 ).setCornersCount( 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 ); + + // 9 10 11 12 13 5 14 15 + meshBuilder.getCellSeed( 1 ).setCornersCount( 8 ); + 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 ) ); + + // Write original decomposed mesh + { + auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V1 >( mesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; + std::ofstream file( "polyhedron_planarTest_orig.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( tetrahedronMesh ); + } + + // Write planar decomposed mesh using 1st version + { + auto planarMesh = getPlanarMesh< PolygonDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V2 >( planarMesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; + std::ofstream file( "polyhedron_planarTest_v1.vtk" ); + VTKWriter writer( file, VTK::FileFormat::ascii ); + writer.template writeEntities( tetrahedronMesh ); + } + + // Write planar decomposed mesh using 2nd version + { + auto planarMesh = getPlanarMesh< PolygonDecomposerVersion::ConnectEdgesToPoint >( mesh ); + auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V1 >( planarMesh ); + using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; + std::ofstream file( "polyhedron_planarTest_v2.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } -- GitLab From 551161cda8c5261112639084ad9d484571617eb8 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Mon, 28 Jun 2021 17:57:53 +0200 Subject: [PATCH 17/42] Meshes/Geometry: refactored polygon and polyhedron decomposition into templated EntityDecomposer struct with specializations --- src/TNL/Meshes/Geometry/EntityDecomposer.h | 235 ++++++++++ src/TNL/Meshes/Geometry/PolygonDecomposer.h | 123 ----- src/TNL/Meshes/Geometry/getDecomposedMesh.h | 485 +++----------------- src/TNL/Meshes/Geometry/getPlanarMesh.h | 97 ++-- src/UnitTests/Meshes/MeshGeometryTest.h | 62 ++- 5 files changed, 392 insertions(+), 610 deletions(-) create mode 100644 src/TNL/Meshes/Geometry/EntityDecomposer.h delete mode 100644 src/TNL/Meshes/Geometry/PolygonDecomposer.h diff --git a/src/TNL/Meshes/Geometry/EntityDecomposer.h b/src/TNL/Meshes/Geometry/EntityDecomposer.h new file mode 100644 index 000000000..ea4ae3b29 --- /dev/null +++ b/src/TNL/Meshes/Geometry/EntityDecomposer.h @@ -0,0 +1,235 @@ +#pragma once + +#include +#include +#include +#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 = typename Devices::Host; + using Topology = typename Topologies::Polygon; + using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; + using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + using PointCreationFunctorType = std::function< GlobalIndexType ( const PointType& ) >; + using DecomposedEntityFunctorType = std::function< void ( GlobalIndexType, GlobalIndexType, GlobalIndexType ) >; + + 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 + } + + static void decompose( const MeshEntityType & entity, + PointCreationFunctorType pointCreationFunctor, + DecomposedEntityFunctorType decomposedEntityFunctor ) + { + 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 ); + decomposedEntityFunctor( v0, v1, v2 ); + } + else { // polygon is decomposed as it has got more than 3 vertices + const auto v0 = pointCreationFunctor( 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 ); + decomposedEntityFunctor( v0, v1, v2 ); + } + { // wrap around term + const auto v1 = entity.template getSubentityIndex< 0 >( verticesCount - 1 ); + const auto v2 = entity.template getSubentityIndex< 0 >( 0 ); + decomposedEntityFunctor( v0, v1, v2 ); + } + } + } +}; + +template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersion > // SubentityDecomposerVersion is not used for polygons +struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion::ConnectEdgesToPoint, SubentityDecomposerVersion > +{ + using Device = typename Devices::Host; + using Topology = typename Topologies::Polygon; + using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; + using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + using PointCreationFunctorType = std::function< GlobalIndexType ( const PointType& ) >; + using DecomposedEntityFunctorType = std::function< void ( GlobalIndexType, GlobalIndexType, GlobalIndexType ) >; + + 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) + } + + static void decompose( const MeshEntityType & entity, + PointCreationFunctorType pointCreationFunctor, + DecomposedEntityFunctorType decomposedEntityFunctor ) + { + // 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 ); + decomposedEntityFunctor( v0, v1, v2 ); + } + } +}; + +// Polyhedron +template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersion > +struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVersion::ConnectEdgesToCentroid, SubentityDecomposerVersion > +{ + using Device = typename Devices::Host; + using CellTopology = typename Topologies::Polyhedron; + using FaceTopology = typename Topologies::Polygon; + using MeshEntityType = MeshEntity< MeshConfig, Device, CellTopology >; + using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + using PointCreationFunctorType = std::function< GlobalIndexType ( const PointType& ) >; + using DecomposedEntityFunctorType = std::function< void ( GlobalIndexType, GlobalIndexType, GlobalIndexType, GlobalIndexType ) >; + 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 }; + } + + static void decompose( const MeshEntityType & entity, + PointCreationFunctorType pointCreationFunctor, + DecomposedEntityFunctorType decomposedEntityFunctor ) + { + const auto & mesh = entity.getMesh(); + const auto v3 = pointCreationFunctor( getEntityCenter( mesh, entity ) ); + + // Lambda for creating tetrahedron from decomposed triangles of faces + auto decomposedSubentityFunctor = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { + decomposedEntityFunctor( 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, pointCreationFunctor, decomposedSubentityFunctor ); + } + } +}; + +template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersion > +struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVersion::ConnectEdgesToPoint, SubentityDecomposerVersion > +{ + // https://mathoverflow.net/a/7672 + using Device = typename Devices::Host; + using CellTopology = typename Topologies::Polyhedron; + using FaceTopology = typename Topologies::Polygon; + using MeshEntityType = MeshEntity< MeshConfig, Device, CellTopology >; + using MeshSubentityType = MeshEntity< MeshConfig, Device, FaceTopology >; + using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; + using PointType = typename VertexMeshEntityType::PointType; + using GlobalIndexType = typename MeshConfig::GlobalIndexType; + using LocalIndexType = typename MeshConfig::LocalIndexType; + using RealType = typename MeshConfig::RealType; + using PointCreationFunctorType = std::function< GlobalIndexType ( const PointType& ) >; + using DecomposedEntityFunctorType = std::function< void ( GlobalIndexType, GlobalIndexType, GlobalIndexType, GlobalIndexType ) >; + 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 }; + } + + static void decompose( const MeshEntityType & entity, + PointCreationFunctorType pointCreationFunctor, + DecomposedEntityFunctorType decomposedEntityFunctor ) + { + 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 decomposedSubentityFunctor = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { + decomposedEntityFunctor( 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, pointCreationFunctor, decomposedSubentityFunctor ); + } + } + } + +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 \ No newline at end of file diff --git a/src/TNL/Meshes/Geometry/PolygonDecomposer.h b/src/TNL/Meshes/Geometry/PolygonDecomposer.h deleted file mode 100644 index 177906df9..000000000 --- a/src/TNL/Meshes/Geometry/PolygonDecomposer.h +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace TNL { -namespace Meshes { - -enum class PolygonDecomposerVersion -{ - ConnectEdgesToCentroid, ConnectEdgesToPoint -}; - -template< typename MeshConfig, PolygonDecomposerVersion > -struct PolygonDecomposer; - -template< typename MeshConfig > -struct PolygonDecomposer< MeshConfig, PolygonDecomposerVersion::ConnectEdgesToCentroid > -{ - using Device = typename Devices::Host; - using Topology = typename Topologies::Polygon; - using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; - using GlobalIndexType = typename MeshConfig::GlobalIndexType; - using LocalIndexType = typename MeshConfig::LocalIndexType; - - static GlobalIndexType getExtraPointsCount( const MeshEntityType & entity ) - { - return 1; - } - - static GlobalIndexType getEntitiesCount( const MeshEntityType & entity ) - { - const auto pointsCount = entity.template getSubentitiesCount< 0 >(); - return ( pointsCount == 3 ) ? 1 : pointsCount; // polygon is decomposed only if it has more than 3 vertices - } - - template< typename MeshType, typename EntitySeedGetterType > - static void decompose( MeshBuilder< MeshType > & meshBuilder, - EntitySeedGetterType entitySeedGetter, - GlobalIndexType & pointsCount, - GlobalIndexType & entitiesCount, - const MeshEntityType & entity ) - { - const auto verticesCount = entity.template getSubentitiesCount< 0 >(); - if( verticesCount == 3 ) { // polygon is not decomposed as it's already a triangle - auto & entitySeed = entitySeedGetter( entitiesCount++ ); - entitySeed.setCornersCount( 3 ); - entitySeed.setCornerId( 0, entity.template getSubentityIndex< 0 >( 0 ) ); - entitySeed.setCornerId( 1, entity.template getSubentityIndex< 0 >( 1 ) ); - entitySeed.setCornerId( 2, entity.template getSubentityIndex< 0 >( 2 ) ); - } - else { // polygon is decomposed as it has got more than 3 vertices - // add centroid of entity to points - const auto entityCenter = getEntityCenter( entity.getMesh(), entity ); - const auto entityCenterIdx = pointsCount++; - meshBuilder.setPoint( entityCenterIdx, entityCenter ); - // decompose polygon into triangles by connecting each edge to the centroid - for( LocalIndexType j = 0, k = 1; k < verticesCount; j++, k++ ) { - auto & entitySeed = entitySeedGetter( entitiesCount++ ); - entitySeed.setCornersCount( 3 ); - entitySeed.setCornerId( 0, entity.template getSubentityIndex< 0 >( j ) ); - entitySeed.setCornerId( 1, entity.template getSubentityIndex< 0 >( k ) ); - entitySeed.setCornerId( 2, entityCenterIdx ); - } - { // wrap around term - auto & entitySeed = entitySeedGetter( entitiesCount++ ); - entitySeed.setCornersCount( 3 ); - entitySeed.setCornerId( 0, entity.template getSubentityIndex< 0 >( verticesCount - 1 ) ); - entitySeed.setCornerId( 1, entity.template getSubentityIndex< 0 >( 0 ) ); - entitySeed.setCornerId( 2, entityCenterIdx ); - } - } - } -}; - -template< typename MeshConfig > -struct PolygonDecomposer< MeshConfig, PolygonDecomposerVersion::ConnectEdgesToPoint > -{ - using Device = typename Devices::Host; - using Topology = typename Topologies::Polygon; - using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; - using GlobalIndexType = typename MeshConfig::GlobalIndexType; - using LocalIndexType = typename MeshConfig::LocalIndexType; - - static GlobalIndexType getExtraPointsCount( const MeshEntityType & entity ) - { - return 0; // No extra points are added - } - - static GlobalIndexType getEntitiesCount( const MeshEntityType & entity ) - { - const auto pointsCount = entity.template getSubentitiesCount< 0 >(); - return pointsCount - 2; // there is a new triangle for every non-adjacent edge to the 0th point - } - - template< typename MeshType, typename EntitySeedGetterType > - static void decompose( MeshBuilder< MeshType > & meshBuilder, - EntitySeedGetterType entitySeedGetter, - GlobalIndexType & pointsCount, - GlobalIndexType & entitiesCount, - const MeshEntityType & entity ) - { - // 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++ ) { - auto & entitySeed = entitySeedGetter( entitiesCount++ ); - const auto v1 = entity.template getSubentityIndex< 0 >( j ); - const auto v2 = entity.template getSubentityIndex< 0 >( k ); - entitySeed.setCornersCount( 3 ); - entitySeed.setCornerId( 0, v0 ); - entitySeed.setCornerId( 1, v1 ); - entitySeed.setCornerId( 2, v2 ); - } - } -}; - -} // namespace Meshes -} // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h index 7f477b8df..beddfdee1 100644 --- a/src/TNL/Meshes/Geometry/getDecomposedMesh.h +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include namespace TNL { namespace Meshes { @@ -21,7 +21,7 @@ struct TriangleConfig: public ParentConfig using CellTopology = Topologies::Triangle; }; -template< PolygonDecomposerVersion version, +template< EntityDecomposerVersion EntityDecomposerVersion, typename MeshConfig, std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true > auto @@ -30,9 +30,10 @@ getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) using TriangleMeshConfig = TriangleConfig< MeshConfig >; using TriangleMesh = Mesh< TriangleMeshConfig, Devices::Host >; using MeshBuilder = MeshBuilder< TriangleMesh >; + using PointType = typename TriangleMesh::PointType; using GlobalIndexType = typename TriangleMesh::GlobalIndexType; using LocalIndexType = typename TriangleMesh::LocalIndexType; - using PolygonDecomposer = PolygonDecomposer< MeshConfig, version >; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion >; TriangleMesh outMesh; MeshBuilder meshBuilder; @@ -43,13 +44,13 @@ getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) // Find the number of points and cells in the outMesh GlobalIndexType outPointsCount = inPointsCount; GlobalIndexType outCellsCount = 0; - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 2 >( i ); - outPointsCount += PolygonDecomposer::getExtraPointsCount( cell ); - outCellsCount += PolygonDecomposer::getEntitiesCount( cell ); + GlobalIndexType extraPointsCount, entitiesCount; + std::tie( extraPointsCount, entitiesCount ) = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + outPointsCount += extraPointsCount; + outCellsCount += entitiesCount; } - meshBuilder.setPointsCount( outPointsCount ); meshBuilder.setCellsCount( outCellsCount ); @@ -59,15 +60,26 @@ getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); } - // Decompose each cell into triangles - auto cellSeedGetter = [&] ( const GlobalIndexType i ) -> auto& { return meshBuilder.getCellSeed( i ); }; - for( GlobalIndexType i = 0, setCellsCount = 0; i < inCellsCount; i++ ) { + // Lambda for creating new points + auto createPointFunc = [&] ( const PointType & point ) { + const auto pointIdx = setPointsCount++; + meshBuilder.setPoint( pointIdx, point ); + return pointIdx; + }; + + // Lambda for setting decomposed triangle in meshBuilder + GlobalIndexType setCellsCount = 0; + auto setDecomposedCellFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { + auto & entitySeed = meshBuilder.getCellSeed( setCellsCount++ ); + entitySeed.setCornerId( 0, v0 ); + entitySeed.setCornerId( 1, v1 ); + entitySeed.setCornerId( 2, v2 ); + }; + + // Decompose each cell + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 2 >( i ); - PolygonDecomposer::decompose( meshBuilder, - cellSeedGetter, - setPointsCount, - setCellsCount, - cell ); + EntityDecomposer::decompose( cell, createPointFunc, setDecomposedCellFunc ); } meshBuilder.build( outMesh ); @@ -81,442 +93,71 @@ struct TetrahedronConfig: public ParentConfig using CellTopology = Topologies::Tetrahedron; }; -enum class GetTetrahedronMeshVersion -{ - V1, V2, V3, V4, V5 -}; - -/** - * Tetrahedrons are made by connecting the triangles of faces to the centroid of cell. - * Triangles of a face are made by connecting each edge to the centroid of a face. - */ -template< typename MeshConfig, - std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > -auto -getTetrahedronMesh_v1( const Mesh< MeshConfig, Devices::Host > & inMesh ) -{ - using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; - using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; - using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; - using LocalIndexType = typename TetrahedronMesh::LocalIndexType; - - TetrahedronMesh outMesh; - MeshBuilder< TetrahedronMesh > meshBuilder; - - const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); - const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); - - // count the number of points and cells in the outMesh - GlobalIndexType outPointsCount = inPointsCount + inCellsCount; // for each cell, there is a new point (centroid of cell) - GlobalIndexType outCellsCount = 0; - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - const auto facesCount = cell.template getSubentitiesCount< 2 >(); - for( LocalIndexType j = 0; j < facesCount; j++ ) { - const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); - const auto face = inMesh.template getEntity< 2 >( faceIdx ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - if( verticesCount == 3 ) { // face is not decomposed as it's already a triangle - outCellsCount++; - } - else { // face is decomposed as it has got more than 3 vertices - outPointsCount++; // for each face of cell, there is a new point (centroid of face) - outCellsCount += verticesCount; // there is verticesCount number of tetrahedrons per face - } - } - } - meshBuilder.setPointsCount( outPointsCount ); - meshBuilder.setCellsCount( outCellsCount ); - - // copy the points from inMesh to outMesh - GlobalIndexType pointSetIdx = 0; - for( ; pointSetIdx < inPointsCount; pointSetIdx++ ) { - meshBuilder.setPoint( pointSetIdx, inMesh.getPoint( pointSetIdx ) ); - } - - // set up cell seeds for the outMesh - for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - - // centroid of the cell connects to triangles of its faces, making tetrahedrons - const auto cellCenter = getEntityCenter( inMesh, cell ); - const auto cellCenterIdx = pointSetIdx++; - meshBuilder.setPoint( cellCenterIdx, cellCenter ); - - const auto facesCount = cell.template getSubentitiesCount< 2 >(); - for( LocalIndexType j = 0; j < facesCount; j++ ) { - const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); - const auto face = inMesh.template getEntity< 2 >( faceIdx ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - - if( verticesCount == 3 ) { // face is a triangle - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - cellSeed.setCornerId( 0, face.template getSubentityIndex< 0 >( 0 ) ); - cellSeed.setCornerId( 1, face.template getSubentityIndex< 0 >( 1 ) ); - cellSeed.setCornerId( 2, face.template getSubentityIndex< 0 >( 2 ) ); - cellSeed.setCornerId( 3, cellCenterIdx ); - } - else { // face is decomposed into triangles as it has got more than 3 vertices - // centroid of the face connects to its edges, making triangles - const auto faceCenter = getEntityCenter( inMesh, face ); - const auto faceCenterIdx = pointSetIdx++; - meshBuilder.setPoint( faceCenterIdx, faceCenter ); - - for( LocalIndexType k = 0, m = 1; m < verticesCount; k++, m++ ) { - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - cellSeed.setCornerId( 0, face.template getSubentityIndex< 0 >( k ) ); - cellSeed.setCornerId( 1, face.template getSubentityIndex< 0 >( m ) ); - cellSeed.setCornerId( 2, faceCenterIdx ); - cellSeed.setCornerId( 3, cellCenterIdx ); - } - { // wrap around term - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - cellSeed.setCornerId( 0, face.template getSubentityIndex< 0 >( verticesCount - 1 ) ); - cellSeed.setCornerId( 1, face.template getSubentityIndex< 0 >( 0 ) ); - cellSeed.setCornerId( 2, faceCenterIdx ); - cellSeed.setCornerId( 3, cellCenterIdx ); - } - } - } - } - - meshBuilder.build( outMesh ); - return outMesh; -} - -/** - * Tetrahedrons are made by connecting the triangles of faces to the centroid of cell. - * Triangles of a face are made by choosing the 0th point of a face and connecting each of its non-adjacent edges to it. - */ -template< typename MeshConfig, +template< EntityDecomposerVersion EntityDecomposerVersion_, + EntityDecomposerVersion SubentityDecomposerVersion, + typename MeshConfig, std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > auto -getTetrahedronMesh_v2( const Mesh< MeshConfig, Devices::Host > & inMesh ) +getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) { using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; using LocalIndexType = typename TetrahedronMesh::LocalIndexType; - + using PointType = typename TetrahedronMesh::PointType; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVersion_, SubentityDecomposerVersion >; + TetrahedronMesh outMesh; MeshBuilder< TetrahedronMesh > meshBuilder; const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); - // count the number of points and cells in the outMesh - GlobalIndexType outPointsCount = inPointsCount + inCellsCount; // for each cell, there is a new point (centroid of cell) + // Find the number of points and cells in the outMesh + GlobalIndexType outPointsCount = inPointsCount; GlobalIndexType outCellsCount = 0; - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 3 >( i ); - const auto facesCount = cell.template getSubentitiesCount< 2 >(); - - for( LocalIndexType j = 0; j < facesCount; j++ ) { - const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); - const auto face = inMesh.template getEntity< 2 >( faceIdx ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - outCellsCount += verticesCount - 2; // there is verticesCount - 2 number of tetrahedrons per face - } + GlobalIndexType extraPointsCount, entitiesCount; + std::tie( extraPointsCount, entitiesCount ) = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + outPointsCount += extraPointsCount; + outCellsCount += entitiesCount; } meshBuilder.setPointsCount( outPointsCount ); meshBuilder.setCellsCount( outCellsCount ); - // copy the points from inMesh to outMesh - GlobalIndexType pointSetIdx = 0; - for( ; pointSetIdx < inPointsCount; pointSetIdx++ ) { - meshBuilder.setPoint( pointSetIdx, inMesh.getPoint( pointSetIdx ) ); - } - - // set up cell seeds for the outMesh - for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - - // centroid of the cell connects to triangles of its faces, making tetrahedrons - const auto cellCenter = getEntityCenter( inMesh, cell ); - const auto cellCenterIdx = pointSetIdx++; - meshBuilder.setPoint( cellCenterIdx, cellCenter ); - - const auto facesCount = cell.template getSubentitiesCount< 2 >(); - for( LocalIndexType j = 0; j < facesCount; j++ ) { - const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); - const auto face = inMesh.template getEntity< 2 >( faceIdx ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - const auto v0 = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles - for( LocalIndexType k = 1, m = 2; m < verticesCount; k++, m++ ) { - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - const auto v1 = face.template getSubentityIndex< 0 >( k ); - const auto v2 = face.template getSubentityIndex< 0 >( m ); - cellSeed.setCornerId( 0, v0 ); - cellSeed.setCornerId( 1, v1 ); - cellSeed.setCornerId( 2, v2 ); - cellSeed.setCornerId( 3, cellCenterIdx ); - } - } - } - - meshBuilder.build( outMesh ); - return outMesh; -} - -/** - * Tetrahedrons are made by choosing the 0th point of a cell and connecting each triangle of its faces to it. - * Triangles of a face are made by choosing the 0th point of a face and connecting each of its non-adjacent edges to it. - */ -template< typename MeshConfig, - std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > -auto -getTetrahedronMesh_v3( const Mesh< MeshConfig, Devices::Host > & inMesh ) -{ - using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; - using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; - using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; - using LocalIndexType = typename TetrahedronMesh::LocalIndexType; - - TetrahedronMesh outMesh; - MeshBuilder< TetrahedronMesh > meshBuilder; - - const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); - const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); - - // outMesh keeps all the points of inMesh - meshBuilder.setPointsCount( inPointsCount ); - for( GlobalIndexType i = 0; i < inPointsCount; i++ ) { - meshBuilder.setPoint( i, inMesh.getPoint( i ) ); - } - - // count the number of cells in the outMesh - GlobalIndexType outCellsCount = 0; - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - const auto facesCount = cell.template getSubentitiesCount< 2 >(); - for( LocalIndexType j = 0; j < facesCount; j++ ) { - const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); - const auto face = inMesh.template getEntity< 2 >( faceIdx ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - outCellsCount += verticesCount - 2; // there is verticesCount - 2 number of tetrahedrons per face - } - } - meshBuilder.setCellsCount( outCellsCount ); - - // set up cell seeds for the outMesh - for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - const auto v3 = cell.template getSubentityIndex< 0 >( 0 ); // point of the cell connects to triangles of its faces, making tetrahedrons - const auto facesCount = cell.template getSubentitiesCount< 2 >(); - for( LocalIndexType j = 0; j < facesCount; j++ ) { - const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); - const auto face = inMesh.template getEntity< 2 >( faceIdx ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - const auto v0 = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles - for( LocalIndexType k = 1, m = 2; m < verticesCount; k++, m++ ) { - const auto v1 = face.template getSubentityIndex< 0 >( k ); - const auto v2 = face.template getSubentityIndex< 0 >( m ); - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - cellSeed.setCornerId( 0, v0 ); - cellSeed.setCornerId( 1, v1 ); - cellSeed.setCornerId( 2, v2 ); - cellSeed.setCornerId( 3, v3 ); - } - } - } - - meshBuilder.build( outMesh ); - return outMesh; -} - -/** - * Tetrahedrons are made by choosing the 0th point of a cell and connecting each triangle of its faces to it. - * Triangles of a face are made by choosing the 0th point of a face and connecting each of its non-adjacent edges to it. - * Additionally, for every tetrahedron, it is checked whether it has non-zero volume. - * If not, given tetrahedron is redundant, thus left out. - */ -template< typename MeshConfig, - std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > -auto -getTetrahedronMesh_v4( const Mesh< MeshConfig, Devices::Host > & inMesh ) -{ - using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; - using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; - using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; - using LocalIndexType = typename TetrahedronMesh::LocalIndexType; - using RealType = typename TetrahedronMesh::RealType; - constexpr RealType precision{ 1e-6 }; - - TetrahedronMesh outMesh; - MeshBuilder< TetrahedronMesh > meshBuilder; - - const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); - const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); - - // outMesh keeps all the points of inMesh - meshBuilder.setPointsCount( inPointsCount ); - for( GlobalIndexType i = 0; i < inPointsCount; i++ ) { - meshBuilder.setPoint( i, inMesh.getPoint( i ) ); - } - - // count the number of cells in the outMesh - GlobalIndexType outCellsCount = 0; - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - const auto v3Idx = cell.template getSubentityIndex< 0 >( 0 ); // point of the cell connects to triangles of its faces, making tetrahedrons - const auto& v3 = inMesh.getPoint( v3Idx ); - const auto facesCount = cell.template getSubentitiesCount< 2 >(); - for( LocalIndexType j = 0; j < facesCount; j++ ) { - const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); - const auto face = inMesh.template getEntity< 2 >( faceIdx ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - const auto v0Idx = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles - const auto& v0 = inMesh.getPoint( v0Idx ); - for( LocalIndexType k = 1, m = 2; m < verticesCount; k++, m++ ) { - const auto v1Idx = face.template getSubentityIndex< 0 >( k ); - const auto& v1 = inMesh.getPoint( v1Idx ); - const auto v2Idx = face.template getSubentityIndex< 0 >( m ); - const auto& v2 = inMesh.getPoint( v2Idx ); - const auto volume = getTetrahedronVolume( v3 - v0, v2 - v0, v1 - v0 ); - if( volume > precision ) { // Leave out redundant tetrahedrons with zero volume - outCellsCount++; - } - } - } - } - meshBuilder.setCellsCount( outCellsCount ); - - // set up cell seeds for the outMesh - for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - const auto v3Idx = cell.template getSubentityIndex< 0 >( 0 ); // point of the cell connects to triangles of its faces, making tetrahedrons - const auto& v3 = inMesh.getPoint( v3Idx ); - const auto facesCount = cell.template getSubentitiesCount< 2 >(); - for( LocalIndexType j = 0; j < facesCount; j++ ) { - const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); - const auto face = inMesh.template getEntity< 2 >( faceIdx ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - const auto v0Idx = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles - const auto& v0 = inMesh.getPoint( v0Idx ); - for( LocalIndexType k = 1, m = 2; m < verticesCount; k++, m++ ) { - const auto v1Idx = face.template getSubentityIndex< 0 >( k ); - const auto& v1 = inMesh.getPoint( v1Idx ); - const auto v2Idx = face.template getSubentityIndex< 0 >( m ); - const auto& v2 = inMesh.getPoint( v2Idx ); - const auto volume = getTetrahedronVolume( v3 - v0, v2 - v0, v1 - v0 ); - if( volume > precision ) { // Leave out redundant tetrahedrons with zero volume - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - cellSeed.setCornerId( 0, v0Idx ); - cellSeed.setCornerId( 1, v1Idx ); - cellSeed.setCornerId( 2, v2Idx ); - cellSeed.setCornerId( 3, v3Idx ); - } - } - } - } - - meshBuilder.build( outMesh ); - return outMesh; -} - -/** - * Tetrahedrons are made by choosing the 0th point of a cell and connecting each triangle of its faces to it. - * Triangles of a face are made by choosing the 0th point of a face and connecting each of its non-adjacent edges to it. - * Additionally, for the first tetrahedron of a face, it is checked whether it has non-zero volume. - * If not, all the tetrahedrons of given face are redundant, thus left out. - * It is also assumed that all of the faces are planar. - */ -template< typename MeshConfig, - std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > -auto -getTetrahedronMesh_v5( const Mesh< MeshConfig, Devices::Host > & inMesh ) -{ - using TetrahedronMeshConfig = TetrahedronConfig< MeshConfig >; - using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; - using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; - using LocalIndexType = typename TetrahedronMesh::LocalIndexType; - using RealType = typename TetrahedronMesh::RealType; - constexpr RealType precision{ 1e-6 }; - - TetrahedronMesh outMesh; - MeshBuilder< TetrahedronMesh > meshBuilder; - - const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); - const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); - - // outMesh keeps all the points of inMesh - meshBuilder.setPointsCount( inPointsCount ); - for( GlobalIndexType i = 0; i < inPointsCount; i++ ) { - meshBuilder.setPoint( i, inMesh.getPoint( i ) ); + // Copy the points from inMesh to outMesh + GlobalIndexType setPointsCount = 0; + for( ; setPointsCount < inPointsCount; setPointsCount++ ) { + meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); } - // count the number of cells in the outMesh - GlobalIndexType outCellsCount = 0; + // Lambda for creating new points + auto createPointFunc = [&] ( const PointType & point ) { + const auto pointIdx = setPointsCount++; + meshBuilder.setPoint( pointIdx, point ); + return pointIdx; + }; + + // Lambda for setting decomposed cells in meshBuilder + GlobalIndexType setCellsCount = 0; + auto setDecomposedCellFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2, GlobalIndexType v3 ) { + auto & entitySeed = meshBuilder.getCellSeed( setCellsCount++ ); + entitySeed.setCornerId( 0, v0 ); + entitySeed.setCornerId( 1, v1 ); + entitySeed.setCornerId( 2, v2 ); + entitySeed.setCornerId( 3, v3 ); + }; + + // Decompose each cell for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 3 >( i ); - const auto v3Idx = cell.template getSubentityIndex< 0 >( 0 ); // point of the cell connects to triangles of its faces, making tetrahedrons - const auto& v3 = inMesh.getPoint( v3Idx ); - const auto facesCount = cell.template getSubentitiesCount< 2 >(); - for( LocalIndexType j = 0; j < facesCount; j++ ) { - const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); - const auto face = inMesh.template getEntity< 2 >( faceIdx ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - const auto v0Idx = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles - const auto& v0 = inMesh.getPoint( v0Idx ); - const auto& v1 = inMesh.getPoint( face.template getSubentityIndex< 0 >( 1 ) ); - const auto& v2 = inMesh.getPoint( face.template getSubentityIndex< 0 >( 2 ) ); - const auto volume = getTetrahedronVolume( v3 - v0, v2 - v0, v1 - v0 ); - if( volume > precision ) { // Leave out redundant faces with zero volume tetrahedrons (It is expected that faces are planar) - outCellsCount += verticesCount - 2; // there is verticesCount - 2 number of tetrahedrons per face - } - } - } - meshBuilder.setCellsCount( outCellsCount ); - - // set up cell seeds for the outMesh - for( GlobalIndexType i = 0, cellSeedIdx = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - const auto v3Idx = cell.template getSubentityIndex< 0 >( 0 ); // point of the cell connects to triangles of its faces, making tetrahedrons - const auto& v3 = inMesh.getPoint( v3Idx ); - const auto facesCount = cell.template getSubentitiesCount< 2 >(); - for( LocalIndexType j = 0; j < facesCount; j++ ) { - const auto faceIdx = cell.template getSubentityIndex< 2 >( j ); - const auto face = inMesh.template getEntity< 2 >( faceIdx ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - const auto v0Idx = face.template getSubentityIndex< 0 >( 0 ); // point of the face connects to its edges, making triangles - const auto& v0 = inMesh.getPoint( v0Idx ); - const auto& v1 = inMesh.getPoint( face.template getSubentityIndex< 0 >( 1 ) ); - const auto& v2 = inMesh.getPoint( face.template getSubentityIndex< 0 >( 2 ) ); - const auto volume = getTetrahedronVolume( v3 - v0, v2 - v0, v1 - v0 ); - if( volume <= precision ) // Leave out redundant faces with zero volume tetrahedrons (It is expected that faces are planar) - continue; - for( LocalIndexType k = 1, m = 2; m < verticesCount; k++, m++ ) { - const auto v1Idx = face.template getSubentityIndex< 0 >( k ); - const auto v2Idx = face.template getSubentityIndex< 0 >( m ); - auto & cellSeed = meshBuilder.getCellSeed( cellSeedIdx++ ); - cellSeed.setCornerId( 0, v0Idx ); - cellSeed.setCornerId( 1, v1Idx ); - cellSeed.setCornerId( 2, v2Idx ); - cellSeed.setCornerId( 3, v3Idx ); - } - } + EntityDecomposer::decompose( cell, createPointFunc, setDecomposedCellFunc ); } meshBuilder.build( outMesh ); return outMesh; } -template< GetTetrahedronMeshVersion version, - typename MeshConfig, - std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > -auto -getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) -{ - switch( version ) - { - case GetTetrahedronMeshVersion::V1: return getTetrahedronMesh_v1( inMesh ); - case GetTetrahedronMeshVersion::V2: return getTetrahedronMesh_v2( inMesh ); - case GetTetrahedronMeshVersion::V3: return getTetrahedronMesh_v3( inMesh ); - case GetTetrahedronMeshVersion::V4: return getTetrahedronMesh_v4( inMesh ); - case GetTetrahedronMeshVersion::V5: return getTetrahedronMesh_v5( inMesh ); - } -} - } // namespace Meshes } // namespace TNL \ No newline at end of file diff --git a/src/TNL/Meshes/Geometry/getPlanarMesh.h b/src/TNL/Meshes/Geometry/getPlanarMesh.h index f80cd7c43..99f9c268d 100644 --- a/src/TNL/Meshes/Geometry/getPlanarMesh.h +++ b/src/TNL/Meshes/Geometry/getPlanarMesh.h @@ -8,13 +8,13 @@ #include #include #include -#include +#include namespace TNL { namespace Meshes { // 3D Polygon Mesh -template< PolygonDecomposerVersion version, +template< EntityDecomposerVersion EntityDecomposerVersion_, 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 > @@ -25,8 +25,9 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) using MeshBuilder = MeshBuilder< PolygonMesh >; using GlobalIndexType = typename PolygonMesh::GlobalIndexType; using LocalIndexType = typename PolygonMesh::LocalIndexType; + using PointType = typename PolygonMesh::PointType; using RealType = typename PolygonMesh::RealType; - using PolygonDecomposer = PolygonDecomposer< MeshConfig, version >; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion_ >; constexpr RealType precision{ 1e-6 }; @@ -39,18 +40,18 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) // find the number of points and cells in the outMesh GlobalIndexType outPointsCount = inPointsCount; GlobalIndexType outCellsCount = 0; - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 2 >( i ); if( isPlanar( inMesh, cell, precision ) ) { // Cell is not decomposed outCellsCount++; } else { // Cell is decomposed - outPointsCount += PolygonDecomposer::getExtraPointsCount( cell ); - outCellsCount += PolygonDecomposer::getEntitiesCount( cell ); + GlobalIndexType extraPointsCount, entitiesCount; + std::tie( extraPointsCount, entitiesCount ) = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + outPointsCount += extraPointsCount; + outCellsCount += entitiesCount; } } - meshBuilder.setPointsCount( outPointsCount ); meshBuilder.setCellsCount( outCellsCount ); @@ -60,8 +61,25 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); } - auto cellSeedGetter = [&] ( const GlobalIndexType i ) -> auto& { return meshBuilder.getCellSeed( i ); }; - for( GlobalIndexType i = 0, setCellsCount = 0; i < inCellsCount; i++ ) { + // Lambda for creating new points + auto createPointFunc = [&] ( const PointType & point ) { + const auto pointIdx = setPointsCount++; + meshBuilder.setPoint( pointIdx, point ); + return pointIdx; + }; + + // Lambda for setting decomposed cells in meshBuilder + GlobalIndexType setCellsCount = 0; + auto setDecomposedCellFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { + auto & entitySeed = meshBuilder.getCellSeed( setCellsCount++ ); + entitySeed.setCornersCount( 3 ); + entitySeed.setCornerId( 0, v0 ); + entitySeed.setCornerId( 1, v1 ); + entitySeed.setCornerId( 2, v2 ); + }; + + // Decompose non-planar cells and copy the rest + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 2 >( i ); if( isPlanar( inMesh, cell, precision ) ) { // Copy planar cells auto & cellSeed = meshBuilder.getCellSeed( setCellsCount++ ); @@ -71,12 +89,8 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) cellSeed.setCornerId( j, cell.template getSubentityIndex< 0 >( j ) ); } } - else { // decompose non-planar cells - PolygonDecomposer::decompose( meshBuilder, - cellSeedGetter, - setPointsCount, - setCellsCount, - cell ); + else { // Decompose non-planar cells + EntityDecomposer::decompose( cell, createPointFunc, setDecomposedCellFunc ); } } @@ -85,7 +99,7 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) } // Polyhedral Mesh -template< PolygonDecomposerVersion version, +template< EntityDecomposerVersion EntityDecomposerVersion_, typename MeshConfig, std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > Mesh< MeshConfig, Devices::Host > @@ -94,9 +108,10 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) using PolyhedronMesh = Mesh< MeshConfig, Devices::Host >; using GlobalIndexType = typename PolyhedronMesh::GlobalIndexType; using LocalIndexType = typename PolyhedronMesh::LocalIndexType; + using PointType = typename PolyhedronMesh::PointType; using RealType = typename PolyhedronMesh::RealType; using FaceMapArray = Containers::Array< std::pair< GlobalIndexType, GlobalIndexType >, Devices::Host, GlobalIndexType >; - using PolygonDecomposer = PolygonDecomposer< MeshConfig, version >; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion_ >; constexpr RealType precision{ 1e-6 }; @@ -107,22 +122,24 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) const GlobalIndexType inFacesCount = inMesh.template getEntitiesCount< 2 >(); const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); - FaceMapArray faceMap( inFacesCount ); + FaceMapArray faceMap( inFacesCount ); // Mapping of original face indeces to a group of decomposed face indices - // find the number of points and faces in the outMesh + // Find the number of points and faces in the outMesh and setup faceMap GlobalIndexType outPointsCount = inPointsCount; GlobalIndexType outFacesCount = 0; for( GlobalIndexType i = 0; i < inFacesCount; i++ ) { const auto face = inMesh.template getEntity< 2 >( i ); - if( isPlanar( inMesh, face, precision ) ) { // + if( isPlanar( inMesh, face, precision ) ) { const auto startFaceIdx = outFacesCount; - const auto endFaceIdx = ++outFacesCount; + const auto endFaceIdx = ++outFacesCount; // Planar faces aren't decomposed faceMap[ i ] = { startFaceIdx, endFaceIdx }; } else { - outPointsCount += PolygonDecomposer::getExtraPointsCount( face ); + GlobalIndexType extraPointsCount, entitiesCount; + std::tie( extraPointsCount, entitiesCount ) = EntityDecomposer::getExtraPointsAndEntitiesCount( face ); + outPointsCount += extraPointsCount; const auto startFaceIdx = outFacesCount; - outFacesCount += PolygonDecomposer::getEntitiesCount( face ); + outFacesCount += entitiesCount; const auto endFaceIdx = outFacesCount; faceMap[ i ] = { startFaceIdx, endFaceIdx }; } @@ -132,12 +149,13 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) meshBuilder.setFacesCount( outFacesCount ); meshBuilder.setCellsCount( inCellsCount ); // The number of cells stays the same - // copy the points from inMesh to outMesh + // Copy the points from inMesh to outMesh GlobalIndexType setPointsCount = 0; for( ; setPointsCount < inPointsCount; setPointsCount++ ) { meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); } + // Set up cell seeds for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 3 >( i ); const LocalIndexType cellFacesCount = cell.template getSubentitiesCount< 2 >(); @@ -162,12 +180,29 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) } } - auto faceSeedGetter = [&] ( const GlobalIndexType i ) -> auto& { return meshBuilder.getFaceSeed( i ); }; - for( GlobalIndexType i = 0, setFacesCount = 0; i < inFacesCount; i++ ) { + // Lambda for creating new points + auto createPointFunc = [&] ( const PointType & point ) { + const auto pointIdx = setPointsCount++; + meshBuilder.setPoint( pointIdx, point ); + return pointIdx; + }; + + // Lambda for setting seed of decomposed triangle + GlobalIndexType setFacesCount = 0; + auto setDecomposedFaceFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { + auto & entitySeed = meshBuilder.getFaceSeed( setFacesCount++ ); + entitySeed.setCornersCount( 3 ); + entitySeed.setCornerId( 0, v0 ); + entitySeed.setCornerId( 1, v1 ); + entitySeed.setCornerId( 2, v2 ); + }; + + // Decompose non-planar faces and copy the rest + for( GlobalIndexType i = 0; i < inFacesCount; i++ ) { const auto face = inMesh.template getEntity< 2 >( i ); const auto verticesCount = face.template getSubentitiesCount< 0 >(); const auto & faceMapping = faceMap[ i ]; - const bool isPlanarRes = ( faceMapping.second - faceMapping.first ) == 1; // face was planar if face maps only onto 1 face + const bool isPlanarRes = ( faceMapping.second - faceMapping.first ) == 1; // Face was planar if face maps only onto 1 face if( isPlanarRes ) { // Copy planar faces auto & faceSeed = meshBuilder.getFaceSeed( setFacesCount++ ); faceSeed.setCornersCount( verticesCount ); @@ -175,12 +210,8 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) faceSeed.setCornerId( j, face.template getSubentityIndex< 0 >( j ) ); } } - else { // decompose non-planar cells - PolygonDecomposer::decompose( meshBuilder, - faceSeedGetter, - setPointsCount, - setFacesCount, - face ); + else { // Decompose non-planar cells + EntityDecomposer::decompose( face, createPointFunc, setDecomposedFaceFunc ); } } diff --git a/src/UnitTests/Meshes/MeshGeometryTest.h b/src/UnitTests/Meshes/MeshGeometryTest.h index 2630e1e65..2eee22790 100644 --- a/src/UnitTests/Meshes/MeshGeometryTest.h +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -553,18 +553,18 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) // Write decomposed mesh using 1st version { - auto triangleMesh = getDecomposedMesh< PolygonDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + auto triangleMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( triangleMesh ) >; - std::ofstream file( "polygon_decompositionTest_v1.vtk" ); + std::ofstream file( "polygon_decompositionTest_c.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( triangleMesh ); } // Write decomposed mesh using 2nd version { - auto triangleMesh = getDecomposedMesh< PolygonDecomposerVersion::ConnectEdgesToPoint >( mesh ); + auto triangleMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( triangleMesh ) >; - std::ofstream file( "polygon_decompositionTest_v2.vtk" ); + std::ofstream file( "polygon_decompositionTest_p.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( triangleMesh ); } @@ -812,45 +812,40 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) // Write decomposed mesh using 1st version { - auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V1 >( mesh ); + auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_decompositionTest_v1.vtk" ); + std::ofstream file( "polyhedron_decompositionTest_cc.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } // Write decomposed mesh using 2nd version { - auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V2 >( mesh ); + auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_decompositionTest_v2.vtk" ); + std::ofstream file( "polyhedron_decompositionTest_cp.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } // Write decomposed mesh using 3rd version { - auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V3 >( mesh ); + auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_decompositionTest_v3.vtk" ); + std::ofstream file( "polyhedron_decompositionTest_pc.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } // Write decomposed mesh using 4th version { - auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V4 >( mesh ); + auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_decompositionTest_v4.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( tetrahedronMesh ); - } - - // Write decomposed mesh using 5th version - { - auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V5 >( mesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_decompositionTest_v5.vtk" ); + std::ofstream file( "polyhedron_decompositionTest_pp.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } @@ -916,18 +911,18 @@ TEST( MeshGeometryTest, Polygon3DGetPlanarMeshTest ) // Write decomposed mesh using 1st version { - auto planarMesh = getPlanarMesh< PolygonDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( planarMesh ) >; - std::ofstream file( "polygon_planarTest_v1.vtk" ); + std::ofstream file( "polygon_planarTest_c.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( planarMesh ); } // Write decomposed mesh using 2nd version { - auto planarMesh = getPlanarMesh< PolygonDecomposerVersion::ConnectEdgesToPoint >( mesh ); + auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( planarMesh ) >; - std::ofstream file( "polygon_planarTest_v2.vtk" ); + std::ofstream file( "polygon_planarTest_p.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( planarMesh ); } @@ -1175,7 +1170,8 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) // Write original decomposed mesh { - auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V1 >( mesh ); + auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; std::ofstream file( "polyhedron_planarTest_orig.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); @@ -1184,20 +1180,22 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) // Write planar decomposed mesh using 1st version { - auto planarMesh = getPlanarMesh< PolygonDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V2 >( planarMesh ); + auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToPoint >( planarMesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_planarTest_v1.vtk" ); + std::ofstream file( "polyhedron_planarTest_c.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } // Write planar decomposed mesh using 2nd version { - auto planarMesh = getPlanarMesh< PolygonDecomposerVersion::ConnectEdgesToPoint >( mesh ); - auto tetrahedronMesh = getDecomposedMesh< GetTetrahedronMeshVersion::V1 >( planarMesh ); + auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToCentroid >( planarMesh ); using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_planarTest_v2.vtk" ); + std::ofstream file( "polyhedron_planarTest_p.vtk" ); VTKWriter writer( file, VTK::FileFormat::ascii ); writer.template writeEntities( tetrahedronMesh ); } -- GitLab From d6396236713a9c0aee2fb25f1006e8ba630e8974 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Mon, 26 Jul 2021 22:02:51 +0200 Subject: [PATCH 18/42] Fix for FPMA reader and added benchmark for polygonal and polyhedral mesh --- src/Benchmarks/CMakeLists.txt | 1 + src/Benchmarks/Mesh/CMakeLists.txt | 8 + src/Benchmarks/Mesh/MemoryInfo.h | 195 +++++++++ src/Benchmarks/Mesh/MeshBenchmarks.h | 450 +++++++++++++++++++++ src/Benchmarks/Mesh/MeshConfigs.h | 138 +++++++ src/Benchmarks/Mesh/tnl-benchmark-mesh.cpp | 1 + src/Benchmarks/Mesh/tnl-benchmark-mesh.cu | 1 + src/Benchmarks/Mesh/tnl-benchmark-mesh.h | 151 +++++++ src/TNL/Meshes/Readers/FPMAReader.h | 91 +++-- 9 files changed, 990 insertions(+), 46 deletions(-) create mode 100644 src/Benchmarks/Mesh/CMakeLists.txt create mode 100644 src/Benchmarks/Mesh/MemoryInfo.h create mode 100644 src/Benchmarks/Mesh/MeshBenchmarks.h create mode 100644 src/Benchmarks/Mesh/MeshConfigs.h create mode 100644 src/Benchmarks/Mesh/tnl-benchmark-mesh.cpp create mode 100644 src/Benchmarks/Mesh/tnl-benchmark-mesh.cu create mode 100644 src/Benchmarks/Mesh/tnl-benchmark-mesh.h diff --git a/src/Benchmarks/CMakeLists.txt b/src/Benchmarks/CMakeLists.txt index 0fc8e0f02..57e8b1861 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 000000000..02964bec2 --- /dev/null +++ b/src/Benchmarks/Mesh/CMakeLists.txt @@ -0,0 +1,8 @@ +if( BUILD_CUDA ) + CUDA_ADD_EXECUTABLE( tnl-benchmark-mesh-cuda tnl-benchmark-mesh.cu ) + install( TARGETS tnl-benchmark-mesh-cuda RUNTIME DESTINATION bin ) +endif() + +ADD_EXECUTABLE( tnl-benchmark-mesh tnl-benchmark-mesh.cpp ) + +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 000000000..2ac56ed5b --- /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 000000000..ce267ea5f --- /dev/null +++ b/src/Benchmarks/Mesh/MeshBenchmarks.h @@ -0,0 +1,450 @@ +/*************************************************************************** + 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: Jakub Klinkovsky + +#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 ) + { + Benchmark::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 >()} + }; + + 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; + } + + benchmark.setMetadataColumns( metadataColumns ); + 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 ); + } + + 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 ); + } + }; + + struct PlanarDispatch + { + template< typename M, + std::enable_if_t< M::Config::spaceDimension == 3, 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, bool > = true > + static void exec( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + } + }; + + struct MeasuresDispatch + { + // 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 ) + { + benchmark.setOperation( String("Measures") ); + exec_helper( benchmark, parameters, mesh ); + + { + benchmark.setOperation( String("Measures (decomp (c))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Measures (decomp (p))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + } + + // 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 ) + { + benchmark.setOperation( String("Measures") ); + exec_helper( benchmark, parameters, mesh ); + + { + benchmark.setOperation( String("Measures (decomp (cc))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Measures (decomp (cp))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Measures (decomp (pc))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Measures (decomp (pp))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + } + private: + template< typename M > + static void exec_helper( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh ) + { + benchmark_measures< Devices::Host >( benchmark, parameters, mesh ); +#ifdef HAVE_CUDA + benchmark_measures< Devices::Cuda >( benchmark, parameters, mesh ); +#endif + } + }; + + struct MemoryDispatch + { + // 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("Memory") ); + benchmark_memory( benchmark, parameters, mesh_src ); + + { + benchmark.setOperation( String("Memory (decomp (c))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); + benchmark_memory( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Memory (decomp (p))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh_src ); + benchmark_memory( benchmark, parameters, decomposedMesh ); + } + } + + // 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("Memory") ); + benchmark_memory( benchmark, parameters, mesh_src ); + + { + benchmark.setOperation( String("Memory (decomp (cc))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); + benchmark_memory( benchmark, parameters, decomposedMesh ); + } + + + { + benchmark.setOperation( String("Memory (decomp (cp))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh_src ); + benchmark_memory( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Memory (decomp (pc))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); + benchmark_memory( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Memory (decomp (pp))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh_src ); + benchmark_memory( benchmark, parameters, decomposedMesh ); + } + } + }; + + static void benchmark_reader( Benchmark & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) + { + 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 ) + { + auto reset = [&]() { + reader->detectMesh(); + }; + + auto benchmark_func = [&] () { + Mesh mesh; + reader->loadMesh( mesh ); + }; + + benchmark.time< Devices::Host >( reset, + "CPU", + benchmark_func ); + } + + // benchmark_decomposition (Polygonal Mesh) + template< EntityDecomposerVersion DecomposerVersion, + typename M, + std::enable_if_t< std::is_same< typename M::Config::CellTopology, Topologies::Polygon >::value, bool > = true > + static void benchmark_decomposition( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + auto benchmark_func = [&] () { + const auto decomposedMesh = getDecomposedMesh< DecomposerVersion >( mesh_src ); + }; + + benchmark.time< Devices::Host >( "CPU", + benchmark_func ); + } + + // benchmark_decomposition (Polyhedral Mesh) + template< EntityDecomposerVersion DecomposerVersion, + EntityDecomposerVersion SubDecomposerVersion, + typename M, + std::enable_if_t< std::is_same< typename M::Config::CellTopology, Topologies::Polyhedron >::value, bool > = true > + static void benchmark_decomposition( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + auto benchmark_func = [&] () { + const auto decomposedMesh = getDecomposedMesh< DecomposerVersion, SubDecomposerVersion >( mesh_src ); + }; + + benchmark.time< Devices::Host >( "CPU", + benchmark_func ); + } + + template< EntityDecomposerVersion DecomposerVersion, + typename M, + std::enable_if_t< M::Config::spaceDimension == 3, bool > = true > + static void benchmark_planar( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + auto benchmark_func = [&] () { + const auto planarMesh = getPlanarMesh< 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 ) + { + MemoryBenchmarkResult memResult = testMemoryUsage( parameters, mesh_src ); + auto noop = [](){}; + benchmark.time< TNL::Devices::Host >( "CPU", noop, memResult ); + } +}; + +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, + Benchmark::MetadataMap metadata, + 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 000000000..765ff58ef --- /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 000000000..b19887b2b --- /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 000000000..b19887b2b --- /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 000000000..f4fc8efcf --- /dev/null +++ b/src/Benchmarks/Mesh/tnl-benchmark-mesh.h @@ -0,0 +1,151 @@ +/*************************************************************************** + 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: Jakub Klinkovsky + +#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, int >::run( std::forward(params)... ) && + MeshBenchmarksRunner< FullConfig, CellTopology, SpaceDimension, float, int, int >::run( std::forward(params)... ); + return status; +} + +bool +resolveCellTopology( Benchmark& benchmark, + Benchmark::MetadataMap metadata, + const Config::ParameterContainer& parameters ) +{ + const String & meshFile = parameters.getParameter< String >( "mesh-file" ); + + benchmark.newBenchmark( meshFile, metadata ); + + 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::Polygon: + switch( reader->getSpaceDimension() ) + { + case 2: + return setMeshParameters< Topologies::Polygon, 2 >( benchmark, metadata, parameters ); + case 3: + return setMeshParameters< Topologies::Polygon, 3 >( benchmark, metadata, parameters ); + default: + std::cerr << "unsupported dimension for polygon mesh: " << reader->getSpaceDimension() << std::endl; + return false; + } + case EntityShape::Polyhedron: + return setMeshParameters< Topologies::Polyhedron >( benchmark, metadata, 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( loops, verbose ); + + // prepare global metadata + Benchmark::MetadataMap metadata = getHardwareMetadata(); + + if( ! resolveCellTopology( benchmark, metadata, parameters ) ) + return EXIT_FAILURE; + + if( ! benchmark.save( logFile ) ) { + std::cerr << "Failed to write the benchmark results to file '" << parameters.getParameter< String >( "log-file" ) << "'." << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/TNL/Meshes/Readers/FPMAReader.h b/src/TNL/Meshes/Readers/FPMAReader.h index 6fce654f5..ece8b7047 100644 --- a/src/TNL/Meshes/Readers/FPMAReader.h +++ b/src/TNL/Meshes/Readers/FPMAReader.h @@ -32,6 +32,7 @@ public: std::istringstream iss; // fpma format doesn't provide types + using PointType = double; pointsType = "double"; connectivityType = offsetsType = "std::int32_t"; @@ -45,11 +46,13 @@ public: std::vector< std::int32_t > faceConnectivityArray, faceOffsetsArray; // read number of points - nextLine( inputFile, iss, line ); - iss >> NumberOfPoints; + NumberOfPoints = readValue< decltype(NumberOfPoints) >( inputFile ); + if( ! inputFile ) { + reset(); + throw MeshReaderError( "FPMAReader", "unable to read number of points, the file may be invalid or corrupted." ); + } // read points - nextLine( inputFile, iss, line ); for( std::size_t pointIndex = 0; pointIndex < NumberOfPoints; pointIndex++ ) { if( ! inputFile ) { reset(); @@ -58,48 +61,39 @@ public: // read the coordinates of a point for( int i = 0; i < 3; i++ ) { - double aux; - iss >> aux; - if( ! iss ) { + 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.push_back( aux ); + pointsArray.emplace_back( aux ); } } // read number of faces - nextLine( inputFile, iss, line ); - iss >> NumberOfFaces; + 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 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 number of points of a face - size_t numberOfFacePoints; - nextLine( inputFile, iss, line ); - iss >> numberOfFacePoints; - // read points of a face for( std::size_t i = 0; i < numberOfFacePoints; i++ ) { - if( ! iss ) { + 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) + "." ); } - - std::uint32_t pointIndex; - iss >> pointIndex; - - if( ! iss || pointIndex >= NumberOfPoints ) { - reset(); - throw MeshReaderError( "FPMAReader", std::to_string(i) + "th component of the face number " + std::to_string(faceIndex) + " is invalid." ); - } - faceConnectivityArray.emplace_back( pointIndex ); } @@ -107,36 +101,29 @@ public: } // read number of cells - nextLine( inputFile, iss, line ); - iss >> NumberOfCells; + 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 faces 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 number of faces of a cell - size_t numberOfCellFaces; - nextLine( inputFile, iss, line ); - iss >> numberOfCellFaces; - // 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) + "." ); } - - std::uint32_t faceIndex; - iss >> faceIndex; - - if( ! iss || faceIndex >= NumberOfFaces ) { - reset(); - throw MeshReaderError( "FPMAReader", std::to_string(i) + "th component of the cell number " + std::to_string(faceIndex) + " is invalid." ); - } - cellConnectivityArray.emplace_back( faceIndex ); } @@ -154,12 +141,24 @@ public: meshType = "Meshes::Mesh"; } private: - void nextLine( std::ifstream& inputFile, std::istringstream& iss, std::string& line ) + template< typename T > + T readValue( std::ifstream& ifs ) { - iss.clear(); - // get next non-empty line, that isn't a comment - while( std::getline( inputFile, line ) && ( line.empty() || line[0] == '#' ) ) {} - iss.str( line ); + 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(); + } } }; -- GitLab From cc40d6accf35abcede51d117cbdbd53f76945da6 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Wed, 4 Aug 2021 22:15:41 +0200 Subject: [PATCH 19/42] removed redundant subentitiesCounts array from SubentityStorageLayer of dimension 1 for polygonal meshes --- .../layers/SubentityStorageLayer.h | 211 +++++++++++++++++- 1 file changed, 210 insertions(+), 1 deletion(-) diff --git a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h index 08861bd23..b00fed832 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -138,7 +138,6 @@ protected: return *this; } - void print( std::ostream& str ) const { BaseType::print( str ); @@ -306,6 +305,216 @@ private: 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, SubdimensionTag::value >; + + SubentityStorageLayer() = default; + + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) + { + operator=( other ); + } + + template< typename Device_ > + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) + { + operator=( other ); + } + + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) + { + BaseType::operator=( other ); + subentitiesCounts = other.subentitiesCounts; + matrix = other.matrix; + return *this; + } + + 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 ); + 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; + } + + using BaseType::getSubentitiesCount; + __cuda_callable__ + LocalIndexType getSubentitiesCount( SubdimensionTag, const GlobalIndexType entityIndex ) const + { + 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; + __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 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, SubdimensionTag::value >; + + SubentityStorageLayer() = default; + + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) + { + operator=( other ); + } + + template< typename Device_ > + SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) + { + operator=( other ); + } + + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) + { + BaseType::operator=( other ); + matrix = other.matrix; + return *this; + } + + 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 ) + {} + + // 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 * -- GitLab From 2a3e7594c9618b57fed8f99fcb7a5f171fa8fd08 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Wed, 4 Aug 2021 23:38:59 +0200 Subject: [PATCH 20/42] added begin and end methods to UnorderedIndexedSet --- src/TNL/Containers/UnorderedIndexedSet.h | 12 +++++- src/TNL/Containers/UnorderedIndexedSet.hpp | 44 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/TNL/Containers/UnorderedIndexedSet.h b/src/TNL/Containers/UnorderedIndexedSet.h index 042a555bc..a90dc64cb 100644 --- a/src/TNL/Containers/UnorderedIndexedSet.h +++ b/src/TNL/Containers/UnorderedIndexedSet.h @@ -32,9 +32,11 @@ 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; @@ -50,6 +52,14 @@ public: 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 4402ab55c..1b4638379 100644 --- a/src/TNL/Containers/UnorderedIndexedSet.hpp +++ b/src/TNL/Containers/UnorderedIndexedSet.hpp @@ -115,6 +115,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, -- GitLab From 6a3e7796f0efb431c4847ca48e2a2bb7c92a7f09 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Mon, 9 Aug 2021 10:19:41 +0200 Subject: [PATCH 21/42] Refactored mesh initialization to reduce number of calls to SubentitySeedsCreator and number of dynamic allocations --- .../initializer/EntityInitializer.h | 43 +++--- .../MeshDetails/initializer/Initializer.h | 92 +++++-------- .../initializer/SubentitySeedsCreator.h | 128 +++++++++++++++++- 3 files changed, 180 insertions(+), 83 deletions(-) diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h index 5671ffd77..d03a6e5f4 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h @@ -124,6 +124,7 @@ class EntityInitializerLayer< MeshConfig, 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 ) @@ -150,13 +151,12 @@ public: for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer, mesh, superentityIndex ); - for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) - { - const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( subentitySeeds[ i ] ); - meshInitializer.template setSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i, subentityIndex ); + 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 ); superentitiesCounts[ subentityIndex ]++; - } + }); } // allocate superentities storage @@ -210,10 +210,13 @@ class EntityInitializerLayer< 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, SuperentityTopology, SubdimensionTag >; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + using SeedType = EntitySeed< MeshConfig, SubentityTopology >; public: static void initSuperentities( InitializerType& meshInitializer, MeshType& mesh ) @@ -236,12 +239,11 @@ public: superentityIndex < mesh.template getEntitiesCount< SuperdimensionTag::value >(); superentityIndex++ ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer, mesh, superentityIndex ); - for( LocalIndexType i = 0; i < subentitySeeds.getSize(); i++ ) - { - const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( subentitySeeds[ i ] ); - meshInitializer.template setSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i, subentityIndex ); - } + 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 ); @@ -282,6 +284,7 @@ class EntityInitializerLayer< MeshConfig, using SuperentityTopology = typename SuperentityTraitsType::EntityTopology; using SubentitySeedsCreatorType = SubentitySeedsCreator< MeshConfig, SuperentityTopology, SubdimensionTag >; using SuperentityMatrixType = typename MeshTraitsType::SuperentityMatrixType; + using SeedType = EntitySeed< MeshConfig, SubentityTopology >; public: static void initSuperentities( InitializerType& meshInitializer, MeshType& mesh ) @@ -298,12 +301,10 @@ public: for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer, mesh, 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 ); superentitiesCounts[ subentityIndex ]++; - } + }); } // allocate superentities storage @@ -315,13 +316,11 @@ public: // initialize superentities storage for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { - auto subentitySeeds = SubentitySeedsCreatorType::create( meshInitializer, mesh, 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 ); - } + }); } BaseType::initSuperentities( meshInitializer, mesh ); diff --git a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index 5f6134c83..eb8e54564 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -251,47 +251,20 @@ protected: 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 CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; using EntitySeedArrayType = Containers::Array< SeedType, typename MeshTraitsType::DeviceType, GlobalIndexType >; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; - + public: - GlobalIndexType getEntitiesCount( InitializerType& initializer, MeshType& mesh ) + void createSeeds( InitializerType& initializer, MeshType& mesh ) { using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, typename MeshTraitsType::CellTopology, DimensionTag >; - SeedSet seedSet; - - for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) - { - auto subentitySeeds = SubentitySeedsCreator::create( initializer, mesh, i ); - for( LocalIndexType j = 0; j < subentitySeeds.getSize(); j++ ) - seedSet.insert( subentitySeeds[ j ] ); + for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) { + SubentitySeedsCreator::iterate( initializer, mesh, i, [&] ( SeedType& seed ) { + this->seedsIndexedSet.insert( seed ); + }); } - - return seedSet.size(); - } - - NeighborCountsArray getCapacities( InitializerType& initializer, MeshType& mesh, const GlobalIndexType numberOfEntities ) - { - using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, typename MeshTraitsType::CellTopology, DimensionTag >; - SeedSet seedSet; - NeighborCountsArray capacities( numberOfEntities ); - GlobalIndexType capSize = 0; - - for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) - { - auto subentitySeeds = SubentitySeedsCreator::create( initializer, mesh, i ); - for( LocalIndexType j = 0; j < subentitySeeds.getSize(); j++ ) - { - const auto& subentitySeed = subentitySeeds[ j ]; - bool inserted = seedSet.insert( subentitySeed ).second; - if( inserted ) - capacities.setElement( capSize++, subentitySeed.getCornersCount() ); - } - } - return capacities; } using BaseType::findEntitySeedIndex; @@ -303,51 +276,56 @@ protected: 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 ); - NeighborCountsArray capacities = getCapacities( initializer, mesh, numberOfEntities ); + + // 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 ); - - using SubentitySeedsCreator = SubentitySeedsCreator< MeshConfig, typename MeshTraitsType::CellTopology, DimensionTag >; - for( GlobalIndexType i = 0; i < mesh.template getEntitiesCount< MeshType::getMeshDimension() >(); i++ ) - { - auto subentitySeeds = SubentitySeedsCreator::create( initializer, mesh, 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 ); - } - } + + // 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 ); } void initEntities( InitializerType& initializer, EntitySeedArrayType& faceSeeds, MeshType& mesh ) { //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; + initializer.template setEntitiesCount< DimensionTag::value >( faceSeeds.getSize() ); + // allocate the subvertex matrix NeighborCountsArray capacities( faceSeeds.getSize() ); - - for( LocalIndexType i = 0; i < capacities.getSize(); i++ ) - capacities[ i ] = faceSeeds[ i ].getCornersCount(); - + for( LocalIndexType i = 0; i < capacities.getSize(); i++ ) { + capacities.setElement( i, faceSeeds[ i ].getCornersCount() ); + } EntityInitializerType::initSubvertexMatrix( capacities, initializer ); - for( GlobalIndexType i = 0; i < faceSeeds.getSize(); i++ ) - { + // initialize the entities + for( GlobalIndexType i = 0; i < faceSeeds.getSize(); i++ ) { const auto& seed = faceSeeds[ i ]; GlobalIndexType entityIndex = this->seedsIndexedSet.insert( seed ); EntityInitializerType::initEntity( entityIndex, seed, initializer ); } + faceSeeds.reset(); EntityInitializerType::initSuperentities( initializer, mesh ); this->seedsIndexedSet.clear(); diff --git a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h index 57a17297f..f09129472 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h +++ b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h @@ -37,9 +37,11 @@ class SubentitySeedsCreator using EntityTraitsType = typename MeshTraitsType::template EntityTraits< EntityTopology::dimension >; using SubentityTraits = typename MeshTraitsType::template SubentityTraits< EntityTopology, SubentityDimensionTag::value >; 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 >; + using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -64,6 +66,27 @@ public: return subentitySeeds; } + 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, SubentitySeedArray::getSize() >( + [&] ( 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; @@ -84,7 +107,9 @@ class SubentitySeedsCreator< MeshConfig, EntityTopology, DimensionTag< 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 >; + using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -96,6 +121,17 @@ public: return seeds; } + 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; @@ -119,6 +155,7 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 1 > public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; + using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -138,6 +175,20 @@ public: return seeds; } + 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 ); @@ -150,6 +201,7 @@ 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; @@ -158,7 +210,9 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 0 > using SubentityTopology = typename SubentityTraits::SubentityTopology; public: - using SubentitySeedArray = Containers::Array< EntitySeed< MeshConfig, SubentityTopology >, Devices::Host, LocalIndexType >; + using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; + using SubentitySeedArray = Containers::Array< SubentitySeed, Devices::Host, LocalIndexType >; + using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -174,6 +228,18 @@ public: return seeds; } + 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 ); @@ -197,6 +263,7 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 2 public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; + using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -222,6 +289,25 @@ public: return seeds; } + static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) + { + const auto& cellSeeds = initializer.getCellSeeds(); + const auto& faces = cellSeeds[ entityIndex ].getCornerIds(); + + for( LocalIndexType i = 0; i < faces.getSize(); i++ ) + { + GlobalIndexType faceIdx = faces[ i ]; + const auto& subvertices = mesh.template getSubentitiesMatrix< 2, 0 >().getRow( faceIdx ); + const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< 2, 0 >( faceIdx ); + SubentitySeed seed; + seed.setCornersCount( subverticesCount ); + for( LocalIndexType j = 0; j < subverticesCount; j++ ) { + seed.setCornerId( j, subvertices.getColumnIndex( j ) ); + } + std::forward< FunctorType >( functor )( seed ); + } + } + static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { auto& cellSeeds = initializer.getCellSeeds(); @@ -248,6 +334,7 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 1 public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; + using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -276,6 +363,22 @@ public: return seeds; } + 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; @@ -312,6 +415,7 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 0 public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; + using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -340,6 +444,22 @@ public: return seeds; } + 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; -- GitLab From 041d60708c43d46518686adf1d0ecceb15f1f00e Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Wed, 25 Aug 2021 11:39:32 +0200 Subject: [PATCH 22/42] Moved the declaration of SubentityMatrixType from MeshSubentityTraits to MeshEntityTraits --- .../MeshDetails/initializer/Initializer.h | 2 +- .../Meshes/MeshDetails/layers/StorageLayer.h | 4 +- .../layers/SubentityStorageLayer.h | 12 +++--- .../MeshDetails/traits/MeshEntityTraits.h | 43 ++++++++++++++----- .../MeshDetails/traits/MeshSubentityTraits.h | 6 --- .../Meshes/MeshDetails/traits/MeshTraits.h | 27 +++++++++--- 6 files changed, 63 insertions(+), 31 deletions(-) diff --git a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index eb8e54564..8dfd3c0db 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -84,7 +84,7 @@ class Initializer using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; template< int Dimension, int Subdimension > - using SubentityMatrixRowsCapacitiesType = typename MeshTraitsType::template SubentityMatrixType< Dimension, Subdimension >::RowsCapacitiesType; + 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, diff --git a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h index 8423cc722..84f312834 100644 --- a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h @@ -113,7 +113,7 @@ public: template< int Dimension, int Subdimension > __cuda_callable__ - typename MeshTraitsType::template SubentityMatrixType< Dimension, Subdimension >& + typename MeshTraitsType::template SubentityMatrixType< Dimension >& getSubentitiesMatrix() { static_assert( Dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); @@ -127,7 +127,7 @@ public: template< int Dimension, int Subdimension > __cuda_callable__ - const typename MeshTraitsType::template SubentityMatrixType< Dimension, Subdimension >& + const typename MeshTraitsType::template SubentityMatrixType< Dimension >& getSubentitiesMatrix() const { static_assert( Dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); diff --git a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h index b00fed832..e3b63c480 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -67,7 +67,7 @@ protected: template< int Subdimension > __cuda_callable__ - typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, Subdimension >& + typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >& getSubentitiesMatrix() { static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); @@ -76,7 +76,7 @@ protected: template< int Subdimension > __cuda_callable__ - const typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, Subdimension >& + const typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >& getSubentitiesMatrix() const { static_assert( EntityTopology::dimension > Subdimension, "Invalid combination of Dimension and Subdimension." ); @@ -108,7 +108,7 @@ class SubentityStorageLayer< MeshConfig, protected: using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; - using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, SubdimensionTag::value >; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; SubentityStorageLayer() = default; @@ -210,7 +210,7 @@ protected: using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; - using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, SubdimensionTag::value >; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; SubentityStorageLayer() = default; @@ -330,7 +330,7 @@ protected: using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; - using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, SubdimensionTag::value >; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; SubentityStorageLayer() = default; @@ -444,7 +444,7 @@ protected: using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; - using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension, SubdimensionTag::value >; + using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; SubentityStorageLayer() = default; diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h index 2bf7f856f..db54ac827 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h @@ -29,25 +29,43 @@ 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 >; + // 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; @@ -60,6 +78,9 @@ public: 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 >; + + // 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 7ab39d200..0f191784e 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshSubentityTraits.h @@ -48,9 +48,6 @@ public: using SubentityTopology = typename MeshEntityTraits< MeshConfig, Device, Dimension >::EntityTopology; using SubentityType = typename MeshEntityTraits< MeshConfig, Device, Dimension >::EntityType; - // container for storing the subentity indices - using SubentityMatrixType = Matrices::SparseMatrix< bool, Device, GlobalIndexType, Matrices::GeneralMatrix, EllpackSegments >; - template< LocalIndexType subentityIndex, LocalIndexType subentityVertexIndex > struct Vertex @@ -86,9 +83,6 @@ public: using SubentityTopology = typename MeshEntityTraits< MeshConfig, Device, Dimension >::EntityTopology; using SubentityType = typename MeshEntityTraits< MeshConfig, Device, Dimension >::EntityType; - - // 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/MeshTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h index d2f128f8e..df079e40b 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h @@ -33,11 +33,28 @@ template< typename MeshConfig, typename Device, typename EntityTopology > class template< typename MeshConfig, typename EntityTopology, - bool variableSize = std::is_same< EntityTopology, Topologies::Polygon >::value || - std::is_same< EntityTopology, Topologies::Polyhedron >::value > + bool IsDynamicTopology = Topologies::IsDynamicTopology< EntityTopology >::value > class EntitySeed; -template< typename MeshConfig, typename Device, int Dimension > class MeshEntityTraits; +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, @@ -93,8 +110,8 @@ public: using DimensionTag = Meshes::DimensionTag< meshDimension >; // container for storing the subentity indices - template< int Dimension, int Subdimension > - using SubentityMatrixType = typename SubentityTraits< typename EntityTraits< Dimension >::EntityTopology, Subdimension >::SubentityMatrixType; + 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 >; -- GitLab From 183033f2c743a4f0abf7a3663d398878d3cf7402 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Tue, 31 Aug 2021 13:06:40 +0200 Subject: [PATCH 23/42] Added EntityInitializerLayer specialization for initializing polyhedron subentites 3 -> 2 from cell seeds + other minor mesh refactoring --- src/Benchmarks/Mesh/tnl-benchmark-mesh.h | 4 +- src/TNL/Containers/UnorderedIndexedSet.h | 4 + src/TNL/Containers/UnorderedIndexedSet.hpp | 23 +++ .../initializer/EntityInitializer.h | 194 ++++++++++++++++-- .../MeshDetails/initializer/Initializer.h | 33 ++- .../initializer/SubentitySeedsCreator.h | 34 ++- .../layers/SubentityStorageLayer.h | 25 +++ src/TNL/Meshes/Readers/FPMAReader.h | 8 +- 8 files changed, 274 insertions(+), 51 deletions(-) diff --git a/src/Benchmarks/Mesh/tnl-benchmark-mesh.h b/src/Benchmarks/Mesh/tnl-benchmark-mesh.h index f4fc8efcf..f814a32be 100644 --- a/src/Benchmarks/Mesh/tnl-benchmark-mesh.h +++ b/src/Benchmarks/Mesh/tnl-benchmark-mesh.h @@ -32,8 +32,8 @@ template< typename CellTopology, bool setMeshParameters( Params&&... params ) { - bool status = MeshBenchmarksRunner< MinimalConfig, CellTopology, SpaceDimension, float, int, int >::run( std::forward(params)... ) && - MeshBenchmarksRunner< FullConfig, CellTopology, SpaceDimension, float, int, int >::run( std::forward(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; } diff --git a/src/TNL/Containers/UnorderedIndexedSet.h b/src/TNL/Containers/UnorderedIndexedSet.h index a90dc64cb..839cf7baa 100644 --- a/src/TNL/Containers/UnorderedIndexedSet.h +++ b/src/TNL/Containers/UnorderedIndexedSet.h @@ -43,10 +43,14 @@ public: 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 ); diff --git a/src/TNL/Containers/UnorderedIndexedSet.hpp b/src/TNL/Containers/UnorderedIndexedSet.hpp index 1b4638379..a29aa2f4d 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, @@ -76,6 +88,17 @@ UnorderedIndexedSet< Key, Index, Hash, KeyEqual, Allocator >::find( const Key& k 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, diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h index d03a6e5f4..936476ed6 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h @@ -28,6 +28,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 @@ -57,7 +58,7 @@ class EntityInitializer using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: - static void initSubvertexMatrix( const NeighborCountsArray& capacities, InitializerType& initializer ) + static void initSubvertexMatrix( NeighborCountsArray& capacities, InitializerType& initializer ) { initializer.template initSubentityMatrix< EntityTopology::dimension, 0 >( capacities ); } @@ -97,10 +98,12 @@ public: */ template< typename MeshConfig, typename SubdimensionTag, - typename SuperdimensionTag > + typename SuperdimensionTag, + typename SuperentityTopology > class EntityInitializerLayer< MeshConfig, SubdimensionTag, SuperdimensionTag, + SuperentityTopology, true, true, true > @@ -120,7 +123,6 @@ class EntityInitializerLayer< MeshConfig, 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, SuperentityTopology, SubdimensionTag >; using SuperentityMatrixType = typename MeshTraitsType::SuperentityMatrixType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; @@ -182,6 +184,101 @@ public: } }; +/**** + * 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 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 >(); + + auto& cellSeeds = meshInitializer.getCellSeeds(); + + NeighborCountsArray capacities( cellSeeds.getSize() ); + + for( GlobalIndexType superentityIndex = 0; superentityIndex < capacities.getSize(); superentityIndex++ ) + capacities[ superentityIndex ] = cellSeeds[ superentityIndex ].getCornersCount(); + + 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 ); + + for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) + { + auto& cellSeed = cellSeeds[ superentityIndex ]; + for( LocalIndexType i = 0; i < cellSeed.getCornersCount(); i++ ) + { + const GlobalIndexType subentityIndex = cellSeed.getCornerIds()[ i ]; + meshInitializer.template setSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i, subentityIndex ); + superentitiesCounts[ subentityIndex ]++; + } + } + cellSeeds.reset(); + + // allocate superentities storage + SuperentityMatrixType& matrix = meshInitializer.template getSuperentitiesMatrix< SubdimensionTag::value, SuperdimensionTag::value >(); + matrix.setDimensions( subentitiesCount, superentitiesCount ); + matrix.setRowCapacities( superentitiesCounts ); + superentitiesCounts.setValue( 0 ); + + // initialize superentities storage + 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 * @@ -190,10 +287,12 @@ public: */ template< typename MeshConfig, typename SubdimensionTag, - typename SuperdimensionTag > + typename SuperdimensionTag, + typename SuperentityTopology > class EntityInitializerLayer< MeshConfig, SubdimensionTag, SuperdimensionTag, + SuperentityTopology, true, false, true > @@ -213,7 +312,6 @@ class EntityInitializerLayer< MeshConfig, 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, SuperentityTopology, SubdimensionTag >; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; using SeedType = EntitySeed< MeshConfig, SubentityTopology >; @@ -234,10 +332,8 @@ public: meshInitializer.template initSubentityMatrix< SuperdimensionTag::value, SubdimensionTag::value >( capacities, subentitiesCount ); } - - for( GlobalIndexType superentityIndex = 0; - superentityIndex < mesh.template getEntitiesCount< SuperdimensionTag::value >(); - superentityIndex++ ) + + for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { LocalIndexType i = 0; SubentitySeedsCreatorType::iterate( meshInitializer, mesh, superentityIndex, [&] ( SeedType& seed ) { @@ -250,6 +346,75 @@ public: } }; +/**** + * 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; + + const GlobalIndexType subentitiesCount = mesh.template getEntitiesCount< SubdimensionTag::value >(); + const GlobalIndexType superentitiesCount = mesh.template getEntitiesCount< SuperdimensionTag::value >(); + + auto& cellSeeds = meshInitializer.getCellSeeds(); + + NeighborCountsArray capacities( cellSeeds.getSize() ); + + for( GlobalIndexType superentityIndex = 0; superentityIndex < capacities.getSize(); superentityIndex++ ) + capacities[ superentityIndex ] = cellSeeds[ superentityIndex ].getCornersCount(); + + meshInitializer.template initSubentityMatrix< SuperdimensionTag::value, SubdimensionTag::value >( capacities, subentitiesCount ); + + for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) + { + auto& cellSeed = cellSeeds[ superentityIndex ]; + for( LocalIndexType i = 0; i < cellSeed.getCornersCount(); i++ ) + { + const GlobalIndexType subentityIndex = cellSeed.getCornerIds()[ i ]; + meshInitializer.template setSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i, subentityIndex ); + } + } + cellSeeds.reset(); + + BaseType::initSuperentities( meshInitializer, mesh ); + } +}; + /**** * Mesh entity initializer layer with specializations * @@ -258,10 +423,12 @@ public: */ template< typename MeshConfig, typename SubdimensionTag, - typename SuperdimensionTag > + typename SuperdimensionTag, + typename SuperentityTopology > class EntityInitializerLayer< MeshConfig, SubdimensionTag, SuperdimensionTag, + SuperentityTopology, false, true, true > @@ -281,7 +448,6 @@ class EntityInitializerLayer< MeshConfig, 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, SuperentityTopology, SubdimensionTag >; using SuperentityMatrixType = typename MeshTraitsType::SuperentityMatrixType; using SeedType = EntitySeed< MeshConfig, SubentityTopology >; @@ -329,10 +495,12 @@ public: template< typename MeshConfig, typename SubdimensionTag, - typename SuperdimensionTag > + typename SuperdimensionTag, + typename SuperentityTopology > class EntityInitializerLayer< MeshConfig, SubdimensionTag, SuperdimensionTag, + SuperentityTopology, false, false, true > @@ -343,11 +511,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/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index 8dfd3c0db..a73fdbfe2 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -109,14 +109,14 @@ class Initializer } template< int Dimension, int Subdimension > - void initSubentityMatrix( const NeighborCountsArray& capacities, 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( capacities.getSize(), subentitiesCount ); matrix.setRowCapacities( capacities ); - mesh->template setSubentitiesCounts< Dimension, Subdimension >( capacities ); + mesh->template setSubentitiesCounts< Dimension, Subdimension >( std::move( capacities ) ); } template< int Dimension > @@ -206,7 +206,7 @@ protected: NeighborCountsArray capacities( cellSeeds.getSize() ); - for( LocalIndexType i = 0; i < capacities.getSize(); i++ ) + for( GlobalIndexType i = 0; i < capacities.getSize(); i++ ) capacities[ i ] = cellSeeds[ i ].getCornersCount(); EntityInitializerType::initSubvertexMatrix( capacities, initializer ); @@ -259,10 +259,11 @@ protected: void createSeeds( InitializerType& initializer, MeshType& mesh ) { + 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( seed ); + this->seedsIndexedSet.insert( std::move( seed ) ); }); } } @@ -306,30 +307,28 @@ protected: BaseType::initEntities( initializer, mesh ); } - void initEntities( InitializerType& initializer, EntitySeedArrayType& faceSeeds, MeshType& mesh ) + void initEntities( InitializerType& initializer, EntitySeedArrayType& seeds, MeshType& mesh ) { //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; - initializer.template setEntitiesCount< DimensionTag::value >( faceSeeds.getSize() ); + initializer.template setEntitiesCount< DimensionTag::value >( seeds.getSize() ); // allocate the subvertex matrix - NeighborCountsArray capacities( faceSeeds.getSize() ); - for( LocalIndexType i = 0; i < capacities.getSize(); i++ ) { - capacities.setElement( i, faceSeeds[ i ].getCornersCount() ); + NeighborCountsArray capacities( seeds.getSize() ); + for( GlobalIndexType i = 0; i < capacities.getSize(); i++ ) { + capacities.setElement( i, seeds[ i ].getCornersCount() ); } EntityInitializerType::initSubvertexMatrix( capacities, initializer ); // initialize the entities - for( GlobalIndexType i = 0; i < faceSeeds.getSize(); i++ ) { - const auto& seed = faceSeeds[ i ]; - GlobalIndexType entityIndex = this->seedsIndexedSet.insert( seed ); - EntityInitializerType::initEntity( entityIndex, seed, initializer ); - } + for( GlobalIndexType i = 0; i < seeds.getSize(); i++ ) + EntityInitializerType::initEntity( i, seeds[ i ], initializer ); + seeds.reset(); - faceSeeds.reset(); + // initialize links between the entities and all superentities EntityInitializerType::initSuperentities( initializer, mesh ); - this->seedsIndexedSet.clear(); - initializer.getCellSeeds().reset(); + + // continue with the next dimension BaseType::initEntities( initializer, mesh ); } diff --git a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h index f09129472..641e96110 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h +++ b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h @@ -41,8 +41,7 @@ class SubentitySeedsCreator public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::StaticArray< SubentityTraits::count, SubentitySeed >; - using FunctorType = std::function< void( SubentitySeed& ) >; - + static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); @@ -66,6 +65,7 @@ public: 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 ); @@ -109,7 +109,6 @@ class SubentitySeedsCreator< MeshConfig, EntityTopology, DimensionTag< 0 > > public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::StaticArray< SubentityTraits::count, SubentitySeed >; - using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -121,6 +120,7 @@ public: 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 ); @@ -155,7 +155,6 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 1 > public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; - using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -175,6 +174,7 @@ public: 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 ); @@ -212,7 +212,6 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 0 > public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::Array< SubentitySeed, Devices::Host, LocalIndexType >; - using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -228,6 +227,7 @@ public: 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 ); @@ -263,7 +263,6 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 2 public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; - using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -289,6 +288,7 @@ public: return seeds; } + template< typename FunctorType > static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) { const auto& cellSeeds = initializer.getCellSeeds(); @@ -334,7 +334,6 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 1 public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; - using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -363,6 +362,7 @@ public: return seeds; } + template< typename FunctorType > static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) { SeedSet seedSet; @@ -384,12 +384,11 @@ public: 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++ ) - { + for( LocalIndexType i = 0; i < facesCount; i++ ) { GlobalIndexType faceIdx = faces.getColumnIndex( i ); - auto faceSubentitySeeds = FaceSubentitySeedsCreator::create( initializer, mesh, faceIdx ); - for( LocalIndexType j = 0; j < faceSubentitySeeds.getSize(); j++ ) - seedSet.insert( faceSubentitySeeds[ j ] ); + FaceSubentitySeedsCreator::iterate( initializer, mesh, faceIdx, [&] ( SubentitySeed& seed ) { + seedSet.insert( seed ); + }); } return seedSet.size(); @@ -415,7 +414,6 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 0 public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; - using FunctorType = std::function< void( SubentitySeed& ) >; static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { @@ -444,6 +442,7 @@ public: return seeds; } + template< typename FunctorType > static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) { SeedSet seedSet; @@ -466,12 +465,11 @@ public: 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++ ) - { + for( LocalIndexType i = 0; i < facesCount; i++ ) { GlobalIndexType faceIdx = faces.getColumnIndex( i ); - auto faceSubentitySeeds = FaceSubentitySeedsCreator::create( initializer, mesh, faceIdx ); - for( LocalIndexType j = 0; j < faceSubentitySeeds.getSize(); j++ ) - seedSet.insert( faceSubentitySeeds[ j ] ); + FaceSubentitySeedsCreator::iterate( initializer, mesh, faceIdx, [&] ( SubentitySeed& seed ) { + seedSet.insert( seed ); + }); } return seedSet.size(); diff --git a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h index e3b63c480..31cd80a18 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -56,6 +56,14 @@ protected: 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 @@ -156,6 +164,9 @@ protected: 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 @@ -276,6 +287,11 @@ protected: subentitiesCounts = counts; } + void setSubentitiesCounts( SubdimensionTag, NeighborCountsArray&& counts ) + { + subentitiesCounts = std::move( counts ); + } + using BaseType::getSubentitiesCount; __cuda_callable__ LocalIndexType getSubentitiesCount( SubdimensionTag, const GlobalIndexType entityIndex ) const @@ -383,6 +399,11 @@ protected: subentitiesCounts = counts; } + void setSubentitiesCounts( SubdimensionTag, NeighborCountsArray&& counts ) + { + subentitiesCounts = std::move( counts ); + } + using BaseType::getSubentitiesCount; __cuda_callable__ LocalIndexType getSubentitiesCount( SubdimensionTag, const GlobalIndexType entityIndex ) const @@ -492,6 +513,9 @@ protected: 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; @@ -574,6 +598,7 @@ protected: } 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/Readers/FPMAReader.h b/src/TNL/Meshes/Readers/FPMAReader.h index ece8b7047..11919c89f 100644 --- a/src/TNL/Meshes/Readers/FPMAReader.h +++ b/src/TNL/Meshes/Readers/FPMAReader.h @@ -51,7 +51,7 @@ public: 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 ) { @@ -78,6 +78,8 @@ public: } // read faces + faceConnectivityArray.reserve( NumberOfFaces ); + faceOffsetsArray.reserve( NumberOfFaces ); for( std::size_t faceIndex = 0; faceIndex < NumberOfFaces; faceIndex++ ) { // read number of points of a face @@ -107,7 +109,9 @@ public: throw MeshReaderError( "FPMAReader", "unable to read number of cells, the file may be invalid or corrupted." ); } - // read faces + // read cells + cellConnectivityArray.reserve( NumberOfCells ); + cellOffsetsArray.reserve( NumberOfCells ); for( std::size_t cellIndex = 0; cellIndex < NumberOfCells; cellIndex++ ) { // read number of faces of a cell -- GitLab From 8585bc52c0212d5f8b0d45c12697ad3fe640321c Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Fri, 3 Sep 2021 19:37:06 +0200 Subject: [PATCH 24/42] Refactored MeshBuilder to store face seed indeces in a matrix instead of array of EntitySeeds --- src/TNL/Meshes/Geometry/EntityDecomposer.h | 20 +- src/TNL/Meshes/Geometry/getPlanarMesh.h | 35 +- src/TNL/Meshes/Mesh.h | 2 +- src/TNL/Meshes/Mesh.hpp | 2 +- src/TNL/Meshes/MeshBuilder.h | 60 ++-- .../initializer/EntityInitializer.h | 18 +- .../initializer/EntitySeedMatrix.h | 318 ++++++++++++++++++ .../MeshDetails/initializer/Initializer.h | 44 +-- .../MeshDetails/traits/MeshEntityTraits.h | 4 +- .../Meshes/MeshDetails/traits/MeshTraits.h | 4 + src/TNL/Meshes/Readers/MeshReader.h | 12 +- src/UnitTests/Meshes/MeshGeometryTest.h | 85 ++--- src/UnitTests/Meshes/MeshTest.h | 44 +-- 13 files changed, 506 insertions(+), 142 deletions(-) create mode 100644 src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h diff --git a/src/TNL/Meshes/Geometry/EntityDecomposer.h b/src/TNL/Meshes/Geometry/EntityDecomposer.h index ea4ae3b29..89e995d8f 100644 --- a/src/TNL/Meshes/Geometry/EntityDecomposer.h +++ b/src/TNL/Meshes/Geometry/EntityDecomposer.h @@ -27,8 +27,8 @@ struct EntityDecomposer; template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersion > // SubentityDecomposerVersion is not used for polygons struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion::ConnectEdgesToCentroid, SubentityDecomposerVersion > { - using Device = typename Devices::Host; - using Topology = typename Topologies::Polygon; + using Device = Devices::Host; + using Topology = Topologies::Polygon; using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; using PointType = typename VertexMeshEntityType::PointType; @@ -76,8 +76,8 @@ struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersio template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersion > // SubentityDecomposerVersion is not used for polygons struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion::ConnectEdgesToPoint, SubentityDecomposerVersion > { - using Device = typename Devices::Host; - using Topology = typename Topologies::Polygon; + using Device = Devices::Host; + using Topology = Topologies::Polygon; using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; using PointType = typename VertexMeshEntityType::PointType; @@ -111,9 +111,9 @@ struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersio template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersion > struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVersion::ConnectEdgesToCentroid, SubentityDecomposerVersion > { - using Device = typename Devices::Host; - using CellTopology = typename Topologies::Polyhedron; - using FaceTopology = typename Topologies::Polygon; + 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 PointType = typename VertexMeshEntityType::PointType; @@ -164,9 +164,9 @@ template< typename MeshConfig, EntityDecomposerVersion SubentityDecomposerVersio struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVersion::ConnectEdgesToPoint, SubentityDecomposerVersion > { // https://mathoverflow.net/a/7672 - using Device = typename Devices::Host; - using CellTopology = typename Topologies::Polyhedron; - using FaceTopology = typename Topologies::Polygon; + 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; diff --git a/src/TNL/Meshes/Geometry/getPlanarMesh.h b/src/TNL/Meshes/Geometry/getPlanarMesh.h index 99f9c268d..e27118374 100644 --- a/src/TNL/Meshes/Geometry/getPlanarMesh.h +++ b/src/TNL/Meshes/Geometry/getPlanarMesh.h @@ -180,6 +180,24 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) } } + // set corners count for face seeds + GlobalIndexType setFacesCount = 0; + for( GlobalIndexType i = 0; i < inFacesCount; i++ ) { + const auto & faceMapping = faceMap[ i ]; + const bool isPlanarRes = ( faceMapping.second - faceMapping.first ) == 1; + if( isPlanarRes ) { + const auto face = inMesh.template getEntity< 2 >( i ); + const auto verticesCount = face.template getSubentitiesCount< 0 >(); + meshBuilder.setFaceCornersCount( setFacesCount++, verticesCount ); + } + else { + for( GlobalIndexType j = faceMapping.first; j < faceMapping.second; j++ ) { + meshBuilder.setFaceCornersCount( setFacesCount++, 3 ); + } + } + } + meshBuilder.initializeFaceSeeds(); + // Lambda for creating new points auto createPointFunc = [&] ( const PointType & point ) { const auto pointIdx = setPointsCount++; @@ -188,13 +206,13 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) }; // Lambda for setting seed of decomposed triangle - GlobalIndexType setFacesCount = 0; + setFacesCount = 0; auto setDecomposedFaceFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { - auto & entitySeed = meshBuilder.getFaceSeed( setFacesCount++ ); - entitySeed.setCornersCount( 3 ); - entitySeed.setCornerId( 0, v0 ); - entitySeed.setCornerId( 1, v1 ); - entitySeed.setCornerId( 2, v2 ); + const GlobalIndexType faceId = setFacesCount++; + auto seed = meshBuilder.getFaceSeed( faceId ); + seed.setCornerId( 0, v0 ); + seed.setCornerId( 1, v1 ); + seed.setCornerId( 2, v2 ); }; // Decompose non-planar faces and copy the rest @@ -204,10 +222,9 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) const auto & faceMapping = faceMap[ i ]; const bool isPlanarRes = ( faceMapping.second - faceMapping.first ) == 1; // Face was planar if face maps only onto 1 face if( isPlanarRes ) { // Copy planar faces - auto & faceSeed = meshBuilder.getFaceSeed( setFacesCount++ ); - faceSeed.setCornersCount( verticesCount ); + const GlobalIndexType faceId = setFacesCount++; for( LocalIndexType j = 0; j < verticesCount; j++ ) { - faceSeed.setCornerId( j, face.template getSubentityIndex< 0 >( j ) ); + meshBuilder.getFaceSeed( faceId ).setCornerId( j, face.template getSubentityIndex< 0 >( j ) ); } } else { // Decompose non-planar cells diff --git a/src/TNL/Meshes/Mesh.h b/src/TNL/Meshes/Mesh.h index c885cf512..8b04acbd4 100644 --- a/src/TNL/Meshes/Mesh.h +++ b/src/TNL/Meshes/Mesh.h @@ -50,7 +50,7 @@ class MeshInitializableBase // The points and cellSeeds arrays will be reset when not needed to save memory. void init( typename MeshTraitsType::PointArrayType& points, - typename MeshTraitsType::FaceSeedArrayType& faceSeeds, + typename MeshTraitsType::FaceSeedMatrixType& faceSeeds, typename MeshTraitsType::CellSeedArrayType& cellSeeds ); }; diff --git a/src/TNL/Meshes/Mesh.hpp b/src/TNL/Meshes/Mesh.hpp index 5e2b72193..d23a33577 100644 --- a/src/TNL/Meshes/Mesh.hpp +++ b/src/TNL/Meshes/Mesh.hpp @@ -27,7 +27,7 @@ template< typename MeshConfig, typename Device, typename MeshType > void MeshInitializableBase< MeshConfig, Device, MeshType >:: init( typename MeshTraitsType::PointArrayType& points, - typename MeshTraitsType::FaceSeedArrayType& faceSeeds, + typename MeshTraitsType::FaceSeedMatrixType& faceSeeds, typename MeshTraitsType::CellSeedArrayType& cellSeeds ) { MeshType* mesh = static_cast< MeshType* >( this ); diff --git a/src/TNL/Meshes/MeshBuilder.h b/src/TNL/Meshes/MeshBuilder.h index cb6fa23b6..626916975 100644 --- a/src/TNL/Meshes/MeshBuilder.h +++ b/src/TNL/Meshes/MeshBuilder.h @@ -25,15 +25,17 @@ 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; - using FaceSeedType = typename MeshTraitsType::FaceSeedType; - + 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; + using CellSeedMatrixType = typename MeshTraitsType::CellSeedMatrixType; + using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; + using FaceSeedType = typename FaceSeedMatrixType::EntitySeedMatrixSeed; + void setPointsCount( const GlobalIndexType& points ) { this->points.setSize( points ); @@ -43,7 +45,17 @@ public: void setFacesCount( const GlobalIndexType& facesCount ) { - this->faceSeeds.setSize( facesCount ); + this->faceSeeds.setDimensions( facesCount, this->points.getSize() ); + } + + void setFaceCornersCount( const GlobalIndexType& faceIndex, const LocalIndexType& cornersCount ) + { + this->faceSeeds.setEntityCornersCount( faceIndex, cornersCount ); + } + + void initializeFaceSeeds() + { + this->faceSeeds.initializeRows(); } void setCellsCount( const GlobalIndexType& cellsCount ) @@ -58,7 +70,7 @@ public: GlobalIndexType getFacesCount() const { - return this->faceSeeds.getSize(); + return this->faceSeeds.getEntitiesCount(); } GlobalIndexType getCellsCount() const @@ -73,9 +85,9 @@ public: this->pointsSet[ index ] = true; } - FaceSeedType& getFaceSeed( GlobalIndexType index ) + FaceSeedType getFaceSeed( GlobalIndexType index ) { - return this->faceSeeds[ index ]; + return this->faceSeeds.getSeed( index ); } CellSeedType& getCellSeed( GlobalIndexType index ) @@ -92,10 +104,10 @@ public: } private: - using PointArrayType = typename MeshTraitsType::PointArrayType; - using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; - using FaceSeedArrayType = typename MeshTraitsType::FaceSeedArrayType; - using BoolVector = Containers::Vector< bool, Devices::Host, GlobalIndexType >; + using PointArrayType = typename MeshTraitsType::PointArrayType; + using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; + using FaceSeedArrayType = typename MeshTraitsType::FaceSeedArrayType; + using BoolVector = Containers::Vector< bool, Devices::Host, GlobalIndexType >; bool validate() const { @@ -129,13 +141,13 @@ private: else { for( GlobalIndexType i = 0; i < getFacesCount(); i++ ) { - const auto& cornerIds = this->faceSeeds[ i ].getCornerIds(); - for( LocalIndexType j = 0; j < cornerIds.getSize(); j++ ) { - if( cornerIds[ j ] < 0 || getPointsCount() <= cornerIds[ j ] ) { - std::cerr << "face seed " << i << " is referencing unavailable point " << cornerIds[ j ] << std::endl; + const auto faceSeed = this->faceSeeds.getSeed( i ); + for( LocalIndexType j = 0; j < faceSeed.getCornersCount(); j++ ) { + if( faceSeed.getCornerId( j ) < 0 || getPointsCount() <= faceSeed.getCornerId( j ) ) { + std::cerr << "face seed " << i << " is referencing unavailable point " << faceSeed.getCornerId( j ) << std::endl; return false; } - assignedPoints[ cornerIds[ j ] ] = true; + assignedPoints[ faceSeed.getCornerId( j ) ] = true; } } @@ -145,7 +157,7 @@ private: } BoolVector assignedFaces; - assignedFaces.setLike( faceSeeds ); + assignedFaces.setSize( faceSeeds.getEntitiesCount() ); assignedFaces.setValue( false ); for( GlobalIndexType i = 0; i < getCellsCount(); i++ ) { @@ -169,7 +181,7 @@ private: } PointArrayType points; - FaceSeedArrayType faceSeeds; + FaceSeedMatrixType faceSeeds; CellSeedArrayType cellSeeds; BoolVector pointsSet; }; diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h index 936476ed6..358c1a18b 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h @@ -49,13 +49,14 @@ 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 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 = EntitySeedMatrix< MeshConfig, EntityTopology >; public: static void initSubvertexMatrix( NeighborCountsArray& capacities, InitializerType& initializer ) @@ -69,6 +70,13 @@ public: for( LocalIndexType i = 0; i < entitySeed.getCornerIds().getSize(); i++ ) initializer.template setSubentityIndex< EntityTopology::dimension, 0 >( entityIndex, i, entitySeed.getCornerIds()[ i ] ); } + + 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() ); + } }; template< typename MeshConfig, diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h new file mode 100644 index 000000000..3e9781d2b --- /dev/null +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h @@ -0,0 +1,318 @@ +#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; + + static constexpr int cornersCount = SubentityTraitsType::count; + + class EntitySeedMatrixSeed + { + using RowView = typename SubentityMatrixType::RowView; + + public: + EntitySeedMatrixSeed( const RowView& matrixRow ) + : row( matrixRow ) + {} + + static constexpr LocalIndexType getCornersCount() + { + 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; + }; + + class ConstEntitySeedMatrixSeed + { + using ConstRowView = typename SubentityMatrixType::ConstRowView; + + public: + ConstEntitySeedMatrixSeed( const ConstRowView& matrixRow ) + : row( matrixRow ) + {} + + static constexpr LocalIndexType getCornersCount() + { + return cornersCount; + } + + 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( cornersCount ); + matrix.setRowCapacities( capacities ); + } + + // This method is only here for compatibility with specialization for dynamic entity topologies + void setEntityCornersCount( const GlobalIndexType& entityIndex, const LocalIndexType& count ) + {} + + // This method is only here for compatibility with specialization for dynamic entity topologies + void initializeRows() + {} + + void reset() + { + matrix.reset(); + } + + void setSeedIndex( const GlobalIndexType& entityIndex, const LocalIndexType& localIndex, const GlobalIndexType& globalIndex ) + { + matrix.getRow( entityIndex ).setElement( localIndex, globalIndex, true ); + } + + GlobalIndexType getEntitiesCount() const + { + return matrix.getRows(); + } + + constexpr LocalIndexType getEntityCornersCount( const GlobalIndexType& entityIndex ) const + { + return cornersCount; + } + + GlobalIndexType getSeedIndex( const GlobalIndexType& entityIndex, const LocalIndexType& localIndex ) const + { + return matrix.getRow( entityIndex ).getColumnIndex( localIndex ); + } + + SubentityMatrixType& getMatrix() + { + return matrix; + } + + const SubentityMatrixType& getMatrix() const + { + return matrix; + } + + NeighborCountsArray getEntityCornerCounts() const + { + NeighborCountsArray counts( getEntitiesCount() ); + counts.setValue( cornersCount ); + 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; + + 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 setEntityCornersCount( const GlobalIndexType& entityIndex, const LocalIndexType& count ) + { + counts.setElement( entityIndex, count ); + } + + void initializeRows() + { + matrix.setRowCapacities( counts ); + } + + void reset() + { + matrix.reset(); + counts.reset(); + } + + void setSeedIndex( const GlobalIndexType& entityIndex, const LocalIndexType& localIndex, const GlobalIndexType& globalIndex ) + { + matrix.getRow( entityIndex ).setElement( localIndex, globalIndex, true ); + } + + GlobalIndexType getEntitiesCount() const + { + return matrix.getRows(); + } + + LocalIndexType getEntityCornersCount( const GlobalIndexType& entityIndex ) const + { + return counts.getElement( entityIndex ); + } + + GlobalIndexType getSeedIndex( const GlobalIndexType& entityIndex, const LocalIndexType& localIndex ) const + { + return matrix.getRow( entityIndex ).getColumnIndex( localIndex ); + } + + 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 \ No newline at end of file diff --git a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index a73fdbfe2..ef840d2b8 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -78,7 +78,7 @@ class Initializer using BaseType = InitializerLayer< MeshConfig, DimensionTag >; using PointArrayType = typename MeshTraitsType::PointArrayType; using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; - using FaceSeedArrayType = typename MeshTraitsType::FaceSeedArrayType; + using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; using GlobalIndexType = typename MeshTraitsType::GlobalIndexType; using LocalIndexType = typename MeshTraitsType::LocalIndexType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; @@ -88,7 +88,7 @@ class Initializer // The points and cellSeeds arrays will be reset when not needed to save memory. void createMesh( PointArrayType& points, - FaceSeedArrayType& faceSeeds, + FaceSeedMatrixType& faceSeeds, CellSeedArrayType& cellSeeds, MeshType& mesh ) { @@ -116,6 +116,12 @@ class Initializer auto& matrix = mesh->template getSubentitiesMatrix< Dimension, Subdimension >(); 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 ) ); } @@ -148,6 +154,14 @@ class Initializer 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() @@ -194,7 +208,7 @@ protected: using InitializerType = Initializer< MeshConfig >; using EntityInitializerType = EntityInitializer< MeshConfig, EntityTopology >; using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; - using FaceSeedArrayType = typename MeshTraitsType::FaceSeedArrayType; + using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: @@ -218,7 +232,7 @@ protected: BaseType::initEntities( initializer, mesh ); } - void initEntities( InitializerType& initializer, FaceSeedArrayType& faceSeeds, MeshType& 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().getSize() ); @@ -252,7 +266,7 @@ protected: using SeedType = EntitySeed< MeshConfig, EntityTopology >; using SeedIndexedSet = typename MeshTraits< MeshConfig >::template EntityTraits< DimensionTag::value >::SeedIndexedSetType; using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; - using EntitySeedArrayType = Containers::Array< SeedType, typename MeshTraitsType::DeviceType, GlobalIndexType >; + using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: @@ -307,23 +321,13 @@ protected: BaseType::initEntities( initializer, mesh ); } - void initEntities( InitializerType& initializer, EntitySeedArrayType& seeds, MeshType& mesh ) + void initEntities( InitializerType& initializer, FaceSeedMatrixType& faceSeeds, MeshType& mesh ) { //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; - initializer.template setEntitiesCount< DimensionTag::value >( seeds.getSize() ); + initializer.template setEntitiesCount< DimensionTag::value >( faceSeeds.getEntitiesCount() ); - // allocate the subvertex matrix - NeighborCountsArray capacities( seeds.getSize() ); - for( GlobalIndexType i = 0; i < capacities.getSize(); i++ ) { - capacities.setElement( i, seeds[ i ].getCornersCount() ); - } - EntityInitializerType::initSubvertexMatrix( capacities, initializer ); - - // initialize the entities - for( GlobalIndexType i = 0; i < seeds.getSize(); i++ ) - EntityInitializerType::initEntity( i, seeds[ i ], initializer ); - seeds.reset(); + EntityInitializerType::initSubvertexMatrix( faceSeeds, initializer ); // initialize links between the entities and all superentities EntityInitializerType::initSuperentities( initializer, mesh ); @@ -354,7 +358,7 @@ class InitializerLayer< MeshConfig, DimensionTag< 0 > > using InitializerType = Initializer< MeshConfig >; using EntityInitializerType = EntityInitializer< MeshConfig, EntityTopology >; using SeedType = EntitySeed< MeshConfig, EntityTopology >; - using EntitySeedArrayType = Containers::Array< SeedType, typename MeshTraitsType::DeviceType, GlobalIndexType >; + using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; public: @@ -370,7 +374,7 @@ class InitializerLayer< MeshConfig, DimensionTag< 0 > > } // This overload is only here for compatibility with Polyhedrons, it is never called - void initEntities( InitializerType& initializer, EntitySeedArrayType& faceSeeds, MeshType& mesh ) + void initEntities( InitializerType& initializer, FaceSeedMatrixType& faceSeeds, MeshType& mesh ) { } }; diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h index db54ac827..f2c4c8d58 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h @@ -48,7 +48,7 @@ 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 >; @@ -75,7 +75,7 @@ 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 >; diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h index df079e40b..4f4d328f2 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,9 @@ public: using PointArrayType = Containers::Array< PointType, DeviceType, GlobalIndexType >; using FaceSeedArrayType = Containers::Array< FaceSeedType, 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 > diff --git a/src/TNL/Meshes/Readers/MeshReader.h b/src/TNL/Meshes/Readers/MeshReader.h index f1188de71..ee23cb35b 100644 --- a/src/TNL/Meshes/Readers/MeshReader.h +++ b/src/TNL/Meshes/Readers/MeshReader.h @@ -197,11 +197,19 @@ public: // 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 ); + std::size_t offsetStart = 0; for( std::size_t i = 0; i < NumberOfFaces; i++ ) { - FaceSeedType& seed = meshBuilder.getFaceSeed( i ); const std::size_t offsetEnd = offsets[ i ]; - seed.setCornersCount( offsetEnd - offsetStart ); + meshBuilder.setFaceCornersCount( i, offsetEnd - offsetStart ); + offsetStart = offsetEnd; + } + meshBuilder.initializeFaceSeeds(); + + offsetStart = 0; + for( std::size_t i = 0; i < NumberOfFaces; i++ ) { + auto 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; diff --git a/src/UnitTests/Meshes/MeshGeometryTest.h b/src/UnitTests/Meshes/MeshGeometryTest.h index 2eee22790..a87932b9c 100644 --- a/src/UnitTests/Meshes/MeshGeometryTest.h +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -266,53 +266,54 @@ TEST( MeshGeometryTest, PolyhedronAreaTest ) meshBuilder.setPoint( 8, point8 ); meshBuilder.setFacesCount( 9 ); + meshBuilder.setFaceCornersCount( 0, 4 ); + meshBuilder.setFaceCornersCount( 1, 4 ); + meshBuilder.setFaceCornersCount( 2, 4 ); + meshBuilder.setFaceCornersCount( 3, 4 ); + meshBuilder.setFaceCornersCount( 4, 4 ); + meshBuilder.setFaceCornersCount( 5, 3 ); + meshBuilder.setFaceCornersCount( 6, 3 ); + meshBuilder.setFaceCornersCount( 7, 3 ); + meshBuilder.setFaceCornersCount( 8, 3 ); + meshBuilder.initializeFaceSeeds(); - meshBuilder.getFaceSeed( 0 ).setCornersCount( 4 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 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 ).setCornersCount( 3 ); meshBuilder.getFaceSeed( 5 ).setCornerId( 0, 4 ); meshBuilder.getFaceSeed( 5 ).setCornerId( 1, 5 ); meshBuilder.getFaceSeed( 5 ).setCornerId( 2, 8 ); - meshBuilder.getFaceSeed( 6 ).setCornersCount( 3 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 0, 5 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 1, 7 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 2, 8 ); - meshBuilder.getFaceSeed( 7 ).setCornersCount( 3 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 0, 7 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 1, 6 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 2, 8 ); - meshBuilder.getFaceSeed( 8 ).setCornersCount( 3 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 0, 6 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 1, 4 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 8 ); @@ -651,9 +652,25 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) */ meshBuilder.setFacesCount( 16 ); + meshBuilder.setFaceCornersCount( 0, 5 ); + meshBuilder.setFaceCornersCount( 1, 4 ); + meshBuilder.setFaceCornersCount( 2, 5 ); + meshBuilder.setFaceCornersCount( 3, 4 ); + meshBuilder.setFaceCornersCount( 4, 5 ); + meshBuilder.setFaceCornersCount( 5, 4 ); + meshBuilder.setFaceCornersCount( 6, 5 ); + meshBuilder.setFaceCornersCount( 7, 5 ); + meshBuilder.setFaceCornersCount( 8, 5 ); + meshBuilder.setFaceCornersCount( 9, 5 ); + meshBuilder.setFaceCornersCount( 10, 5 ); + meshBuilder.setFaceCornersCount( 11, 6 ); + meshBuilder.setFaceCornersCount( 12, 3 ); + meshBuilder.setFaceCornersCount( 13, 4 ); + meshBuilder.setFaceCornersCount( 14, 4 ); + meshBuilder.setFaceCornersCount( 15, 5 ); + meshBuilder.initializeFaceSeeds(); // 0 1 2 3 4 - meshBuilder.getFaceSeed( 0 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getFaceSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getFaceSeed( 0 ).setCornerId( 2, 2 ); @@ -661,14 +678,12 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getFaceSeed( 0 ).setCornerId( 4, 4 ); // 4 3 5 6 - meshBuilder.getFaceSeed( 1 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 2 ).setCornerId( 0, 5 ); meshBuilder.getFaceSeed( 2 ).setCornerId( 1, 3 ); meshBuilder.getFaceSeed( 2 ).setCornerId( 2, 2 ); @@ -676,14 +691,12 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getFaceSeed( 2 ).setCornerId( 4, 8 ); // 9 1 0 10 - meshBuilder.getFaceSeed( 3 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 4 ).setCornerId( 0, 11 ); meshBuilder.getFaceSeed( 4 ).setCornerId( 1, 7 ); meshBuilder.getFaceSeed( 4 ).setCornerId( 2, 2 ); @@ -691,14 +704,12 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getFaceSeed( 4 ).setCornerId( 4, 9 ); // 8 7 11 12 - meshBuilder.getFaceSeed( 5 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 0, 13 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 1, 12 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 2, 11 ); @@ -706,7 +717,6 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getFaceSeed( 6 ).setCornerId( 4, 10 ); // 13 10 0 4 6 - meshBuilder.getFaceSeed( 7 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 0, 13 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 1, 10 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 2, 0 ); @@ -714,7 +724,6 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getFaceSeed( 7 ).setCornerId( 4, 6 ); // 13 6 5 8 12 - meshBuilder.getFaceSeed( 8 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 0, 13 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 1, 6 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 5 ); @@ -722,7 +731,6 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getFaceSeed( 8 ).setCornerId( 4, 12 ); // 8 7 14 15 16 - meshBuilder.getFaceSeed( 9 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 9 ).setCornerId( 0, 8 ); meshBuilder.getFaceSeed( 9 ).setCornerId( 1, 7 ); meshBuilder.getFaceSeed( 9 ).setCornerId( 2, 14 ); @@ -730,7 +738,6 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getFaceSeed( 9 ).setCornerId( 4, 16 ); // 16 15 17 18 19 - meshBuilder.getFaceSeed( 10 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 10 ).setCornerId( 0, 16 ); meshBuilder.getFaceSeed( 10 ).setCornerId( 1, 15 ); meshBuilder.getFaceSeed( 10 ).setCornerId( 2, 17 ); @@ -738,7 +745,6 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getFaceSeed( 10 ).setCornerId( 4, 19 ); // 20 18 17 14 7 11 - meshBuilder.getFaceSeed( 11 ).setCornersCount( 6 ); meshBuilder.getFaceSeed( 11 ).setCornerId( 0, 20 ); meshBuilder.getFaceSeed( 11 ).setCornerId( 1, 18 ); meshBuilder.getFaceSeed( 11 ).setCornerId( 2, 17 ); @@ -747,27 +753,23 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getFaceSeed( 11 ).setCornerId( 5, 11 ); // 17 15 14 - meshBuilder.getFaceSeed( 12 ).setCornersCount( 3 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 15 ).setCornerId( 0, 12 ); meshBuilder.getFaceSeed( 15 ).setCornerId( 1, 8 ); meshBuilder.getFaceSeed( 15 ).setCornerId( 2, 16 ); @@ -1009,9 +1011,25 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) */ meshBuilder.setFacesCount( 16 ); + meshBuilder.setFaceCornersCount( 0, 5 ); + meshBuilder.setFaceCornersCount( 1, 4 ); + meshBuilder.setFaceCornersCount( 2, 5 ); + meshBuilder.setFaceCornersCount( 3, 4 ); + meshBuilder.setFaceCornersCount( 4, 5 ); + meshBuilder.setFaceCornersCount( 5, 4 ); + meshBuilder.setFaceCornersCount( 6, 5 ); + meshBuilder.setFaceCornersCount( 7, 5 ); + meshBuilder.setFaceCornersCount( 8, 5 ); + meshBuilder.setFaceCornersCount( 9, 5 ); + meshBuilder.setFaceCornersCount( 10, 5 ); + meshBuilder.setFaceCornersCount( 11, 6 ); + meshBuilder.setFaceCornersCount( 12, 3 ); + meshBuilder.setFaceCornersCount( 13, 4 ); + meshBuilder.setFaceCornersCount( 14, 4 ); + meshBuilder.setFaceCornersCount( 15, 5 ); + meshBuilder.initializeFaceSeeds(); // 0 1 2 3 4 - meshBuilder.getFaceSeed( 0 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getFaceSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getFaceSeed( 0 ).setCornerId( 2, 2 ); @@ -1019,14 +1037,12 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) meshBuilder.getFaceSeed( 0 ).setCornerId( 4, 4 ); // 4 3 5 6 - meshBuilder.getFaceSeed( 1 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 2 ).setCornerId( 0, 5 ); meshBuilder.getFaceSeed( 2 ).setCornerId( 1, 3 ); meshBuilder.getFaceSeed( 2 ).setCornerId( 2, 2 ); @@ -1034,14 +1050,12 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) meshBuilder.getFaceSeed( 2 ).setCornerId( 4, 8 ); // 9 1 0 10 - meshBuilder.getFaceSeed( 3 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 4 ).setCornerId( 0, 11 ); meshBuilder.getFaceSeed( 4 ).setCornerId( 1, 7 ); meshBuilder.getFaceSeed( 4 ).setCornerId( 2, 2 ); @@ -1049,14 +1063,12 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) meshBuilder.getFaceSeed( 4 ).setCornerId( 4, 9 ); // 8 7 11 12 - meshBuilder.getFaceSeed( 5 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 0, 13 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 1, 12 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 2, 11 ); @@ -1064,7 +1076,6 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) meshBuilder.getFaceSeed( 6 ).setCornerId( 4, 10 ); // 13 10 0 4 6 - meshBuilder.getFaceSeed( 7 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 0, 13 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 1, 10 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 2, 0 ); @@ -1072,7 +1083,6 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) meshBuilder.getFaceSeed( 7 ).setCornerId( 4, 6 ); // 13 6 5 8 12 - meshBuilder.getFaceSeed( 8 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 0, 13 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 1, 6 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 5 ); @@ -1080,7 +1090,6 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) meshBuilder.getFaceSeed( 8 ).setCornerId( 4, 12 ); // 8 7 14 15 16 - meshBuilder.getFaceSeed( 9 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 9 ).setCornerId( 0, 8 ); meshBuilder.getFaceSeed( 9 ).setCornerId( 1, 7 ); meshBuilder.getFaceSeed( 9 ).setCornerId( 2, 14 ); @@ -1088,7 +1097,6 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) meshBuilder.getFaceSeed( 9 ).setCornerId( 4, 16 ); // 16 15 17 18 19 - meshBuilder.getFaceSeed( 10 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 10 ).setCornerId( 0, 16 ); meshBuilder.getFaceSeed( 10 ).setCornerId( 1, 15 ); meshBuilder.getFaceSeed( 10 ).setCornerId( 2, 17 ); @@ -1096,7 +1104,6 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) meshBuilder.getFaceSeed( 10 ).setCornerId( 4, 19 ); // 20 18 17 14 7 11 - meshBuilder.getFaceSeed( 11 ).setCornersCount( 6 ); meshBuilder.getFaceSeed( 11 ).setCornerId( 0, 20 ); meshBuilder.getFaceSeed( 11 ).setCornerId( 1, 18 ); meshBuilder.getFaceSeed( 11 ).setCornerId( 2, 17 ); @@ -1105,27 +1112,23 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) meshBuilder.getFaceSeed( 11 ).setCornerId( 5, 11 ); // 17 15 14 - meshBuilder.getFaceSeed( 12 ).setCornersCount( 3 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 15 ).setCornerId( 0, 12 ); meshBuilder.getFaceSeed( 15 ).setCornerId( 1, 8 ); meshBuilder.getFaceSeed( 15 ).setCornerId( 2, 16 ); diff --git a/src/UnitTests/Meshes/MeshTest.h b/src/UnitTests/Meshes/MeshTest.h index 040eb07e9..4ba992bf0 100644 --- a/src/UnitTests/Meshes/MeshTest.h +++ b/src/UnitTests/Meshes/MeshTest.h @@ -1069,26 +1069,15 @@ TEST( MeshTest, TwoPolygonsTest ) meshBuilder.setCellsCount( 2 ); meshBuilder.getCellSeed( 0 ).setCornersCount( 4 ); - EXPECT_EQ( meshBuilder.getCellSeed( 0 ).getCornersCount(), 4 ); - meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); meshBuilder.getCellSeed( 0 ).setCornerId( 3, 3 ); - EXPECT_EQ( meshBuilder.getCellSeed( 0 ).getCornerIds() [ 0 ], 0 ); - EXPECT_EQ( meshBuilder.getCellSeed( 0 ).getCornerIds() [ 1 ], 1 ); - EXPECT_EQ( meshBuilder.getCellSeed( 0 ).getCornerIds() [ 2 ], 2 ); - EXPECT_EQ( meshBuilder.getCellSeed( 0 ).getCornerIds() [ 3 ], 3 ); meshBuilder.getCellSeed( 1 ).setCornersCount( 3 ); - EXPECT_EQ( meshBuilder.getCellSeed( 1 ).getCornersCount(), 3 ); - meshBuilder.getCellSeed( 1 ).setCornerId( 0, 3 ); meshBuilder.getCellSeed( 1 ).setCornerId( 1, 2 ); meshBuilder.getCellSeed( 1 ).setCornerId( 2, 4 ); - EXPECT_EQ( meshBuilder.getCellSeed( 1 ).getCornerIds() [ 0 ], 3 ); - EXPECT_EQ( meshBuilder.getCellSeed( 1 ).getCornerIds() [ 1 ], 2 ); - EXPECT_EQ( meshBuilder.getCellSeed( 1 ).getCornerIds() [ 2 ], 4 ); ASSERT_TRUE( meshBuilder.build( mesh ) ); @@ -2652,9 +2641,25 @@ TEST( MeshTest, TwoPolyhedronsTest ) */ meshBuilder.setFacesCount( 16 ); + meshBuilder.setFaceCornersCount( 0, 5 ); + meshBuilder.setFaceCornersCount( 1, 4 ); + meshBuilder.setFaceCornersCount( 2, 5 ); + meshBuilder.setFaceCornersCount( 3, 4 ); + meshBuilder.setFaceCornersCount( 4, 5 ); + meshBuilder.setFaceCornersCount( 5, 4 ); + meshBuilder.setFaceCornersCount( 6, 5 ); + meshBuilder.setFaceCornersCount( 7, 5 ); + meshBuilder.setFaceCornersCount( 8, 5 ); + meshBuilder.setFaceCornersCount( 9, 5 ); + meshBuilder.setFaceCornersCount( 10, 5 ); + meshBuilder.setFaceCornersCount( 11, 6 ); + meshBuilder.setFaceCornersCount( 12, 3 ); + meshBuilder.setFaceCornersCount( 13, 4 ); + meshBuilder.setFaceCornersCount( 14, 4 ); + meshBuilder.setFaceCornersCount( 15, 5 ); + meshBuilder.initializeFaceSeeds(); // 0 1 2 3 4 - meshBuilder.getFaceSeed( 0 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getFaceSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getFaceSeed( 0 ).setCornerId( 2, 2 ); @@ -2662,14 +2667,12 @@ TEST( MeshTest, TwoPolyhedronsTest ) meshBuilder.getFaceSeed( 0 ).setCornerId( 4, 4 ); // 4 3 5 6 - meshBuilder.getFaceSeed( 1 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 2 ).setCornerId( 0, 5 ); meshBuilder.getFaceSeed( 2 ).setCornerId( 1, 3 ); meshBuilder.getFaceSeed( 2 ).setCornerId( 2, 2 ); @@ -2677,14 +2680,12 @@ TEST( MeshTest, TwoPolyhedronsTest ) meshBuilder.getFaceSeed( 2 ).setCornerId( 4, 8 ); // 9 1 0 10 - meshBuilder.getFaceSeed( 3 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 4 ).setCornerId( 0, 11 ); meshBuilder.getFaceSeed( 4 ).setCornerId( 1, 7 ); meshBuilder.getFaceSeed( 4 ).setCornerId( 2, 2 ); @@ -2692,14 +2693,12 @@ TEST( MeshTest, TwoPolyhedronsTest ) meshBuilder.getFaceSeed( 4 ).setCornerId( 4, 9 ); // 8 7 11 12 - meshBuilder.getFaceSeed( 5 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 0, 13 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 1, 12 ); meshBuilder.getFaceSeed( 6 ).setCornerId( 2, 11 ); @@ -2707,7 +2706,6 @@ TEST( MeshTest, TwoPolyhedronsTest ) meshBuilder.getFaceSeed( 6 ).setCornerId( 4, 10 ); // 13 10 0 4 6 - meshBuilder.getFaceSeed( 7 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 0, 13 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 1, 10 ); meshBuilder.getFaceSeed( 7 ).setCornerId( 2, 0 ); @@ -2715,7 +2713,6 @@ TEST( MeshTest, TwoPolyhedronsTest ) meshBuilder.getFaceSeed( 7 ).setCornerId( 4, 6 ); // 13 6 5 8 12 - meshBuilder.getFaceSeed( 8 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 0, 13 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 1, 6 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 5 ); @@ -2723,7 +2720,6 @@ TEST( MeshTest, TwoPolyhedronsTest ) meshBuilder.getFaceSeed( 8 ).setCornerId( 4, 12 ); // 8 7 14 15 16 - meshBuilder.getFaceSeed( 9 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 9 ).setCornerId( 0, 8 ); meshBuilder.getFaceSeed( 9 ).setCornerId( 1, 7 ); meshBuilder.getFaceSeed( 9 ).setCornerId( 2, 14 ); @@ -2731,7 +2727,6 @@ TEST( MeshTest, TwoPolyhedronsTest ) meshBuilder.getFaceSeed( 9 ).setCornerId( 4, 16 ); // 16 15 17 18 19 - meshBuilder.getFaceSeed( 10 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 10 ).setCornerId( 0, 16 ); meshBuilder.getFaceSeed( 10 ).setCornerId( 1, 15 ); meshBuilder.getFaceSeed( 10 ).setCornerId( 2, 17 ); @@ -2739,7 +2734,6 @@ TEST( MeshTest, TwoPolyhedronsTest ) meshBuilder.getFaceSeed( 10 ).setCornerId( 4, 19 ); // 20 18 17 14 7 11 - meshBuilder.getFaceSeed( 11 ).setCornersCount( 6 ); meshBuilder.getFaceSeed( 11 ).setCornerId( 0, 20 ); meshBuilder.getFaceSeed( 11 ).setCornerId( 1, 18 ); meshBuilder.getFaceSeed( 11 ).setCornerId( 2, 17 ); @@ -2748,27 +2742,23 @@ TEST( MeshTest, TwoPolyhedronsTest ) meshBuilder.getFaceSeed( 11 ).setCornerId( 5, 11 ); // 17 15 14 - meshBuilder.getFaceSeed( 12 ).setCornersCount( 3 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getFaceSeed( 15 ).setCornerId( 0, 12 ); meshBuilder.getFaceSeed( 15 ).setCornerId( 1, 8 ); meshBuilder.getFaceSeed( 15 ).setCornerId( 2, 16 ); -- GitLab From a63b17cd15c65c0a5df04d1c5314f2647c702e89 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Sat, 4 Sep 2021 10:18:03 +0200 Subject: [PATCH 25/42] Refactored MeshBuilder to store cell seed indeces in a matrix instead of array of EntitySeeds --- src/TNL/Meshes/Geometry/getDecomposedMesh.h | 4 +- src/TNL/Meshes/Geometry/getPlanarMesh.h | 83 +++++++--- src/TNL/Meshes/Mesh.h | 2 +- src/TNL/Meshes/Mesh.hpp | 2 +- src/TNL/Meshes/MeshBuilder.h | 56 ++++--- .../initializer/EntityInitializer.h | 66 +++----- .../initializer/EntitySeedMatrix.h | 154 ++++++++++++++---- .../MeshDetails/initializer/Initializer.h | 52 ++---- .../initializer/SubentitySeedsCreator.h | 16 +- .../MeshDetails/traits/MeshEntityTraits.h | 2 + src/TNL/Meshes/Readers/MeshReader.h | 14 +- src/UnitTests/Meshes/MeshGeometryTest.h | 54 +++--- src/UnitTests/Meshes/MeshTest.h | 28 ++-- 13 files changed, 330 insertions(+), 203 deletions(-) diff --git a/src/TNL/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h index beddfdee1..6c51c8884 100644 --- a/src/TNL/Meshes/Geometry/getDecomposedMesh.h +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -70,7 +70,7 @@ getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) // Lambda for setting decomposed triangle in meshBuilder GlobalIndexType setCellsCount = 0; auto setDecomposedCellFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { - auto & entitySeed = meshBuilder.getCellSeed( setCellsCount++ ); + auto entitySeed = meshBuilder.getCellSeed( setCellsCount++ ); entitySeed.setCornerId( 0, v0 ); entitySeed.setCornerId( 1, v1 ); entitySeed.setCornerId( 2, v2 ); @@ -142,7 +142,7 @@ getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) // Lambda for setting decomposed cells in meshBuilder GlobalIndexType setCellsCount = 0; auto setDecomposedCellFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2, GlobalIndexType v3 ) { - auto & entitySeed = meshBuilder.getCellSeed( setCellsCount++ ); + auto entitySeed = meshBuilder.getCellSeed( setCellsCount++ ); entitySeed.setCornerId( 0, v0 ); entitySeed.setCornerId( 1, v1 ); entitySeed.setCornerId( 2, v2 ); diff --git a/src/TNL/Meshes/Geometry/getPlanarMesh.h b/src/TNL/Meshes/Geometry/getPlanarMesh.h index e27118374..919eae67d 100644 --- a/src/TNL/Meshes/Geometry/getPlanarMesh.h +++ b/src/TNL/Meshes/Geometry/getPlanarMesh.h @@ -27,6 +27,7 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) using LocalIndexType = typename PolygonMesh::LocalIndexType; using PointType = typename PolygonMesh::PointType; using RealType = typename PolygonMesh::RealType; + using BoolVector = Containers::Vector< bool, Devices::Host, GlobalIndexType >; using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion_ >; constexpr RealType precision{ 1e-6 }; @@ -37,12 +38,17 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 2 >(); - // find the number of points and cells in the outMesh + BoolVector planarCache; + planarCache.setSize( inCellsCount ); + + // Count the number of points and cells in the outMesh GlobalIndexType outPointsCount = inPointsCount; GlobalIndexType outCellsCount = 0; for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 2 >( i ); - if( isPlanar( inMesh, cell, precision ) ) { // Cell is not decomposed + const bool planar = isPlanar( inMesh, cell, precision ); + planarCache.setElement( i, planar ); + if( planar ) { // Cell is not decomposed outCellsCount++; } else { // Cell is decomposed @@ -62,31 +68,48 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) } // Lambda for creating new points - auto createPointFunc = [&] ( const PointType & point ) { + auto createPointFunc = [&] ( const PointType& point ) { const auto pointIdx = setPointsCount++; meshBuilder.setPoint( pointIdx, point ); return pointIdx; }; - // Lambda for setting decomposed cells in meshBuilder + // set corner counts for cells + for( GlobalIndexType i = 0, o = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 2 >( i ); + const bool planar = planarCache[ i ]; + if( planar ) { // Copy planar cells + const auto verticesCount = cell.template getSubentitiesCount< 0 >(); + meshBuilder.setCellCornersCount( o++, verticesCount ); + } + else { // Decompose non-planar cells + GlobalIndexType entitiesCount; + std::tie( std::ignore, entitiesCount ) = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + for( GlobalIndexType j = 0; j < entitiesCount; j++ ) { + meshBuilder.setCellCornersCount( o++, 3 ); + } + } + } + meshBuilder.initializeCellSeeds(); + + // Lambda for setting corner ids of decomposed cells GlobalIndexType setCellsCount = 0; auto setDecomposedCellFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { - auto & entitySeed = meshBuilder.getCellSeed( setCellsCount++ ); - entitySeed.setCornersCount( 3 ); - entitySeed.setCornerId( 0, v0 ); - entitySeed.setCornerId( 1, v1 ); - entitySeed.setCornerId( 2, v2 ); + auto seed = meshBuilder.getCellSeed( setCellsCount++ ); + seed.setCornerId( 0, v0 ); + seed.setCornerId( 1, v1 ); + seed.setCornerId( 2, v2 ); }; // Decompose non-planar cells and copy the rest for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 2 >( i ); - if( isPlanar( inMesh, cell, precision ) ) { // Copy planar cells - auto & cellSeed = meshBuilder.getCellSeed( setCellsCount++ ); + const bool planar = planarCache[ i ]; + if( planar ) { // Copy planar cells + auto seed = meshBuilder.getCellSeed( setCellsCount++ ); const auto verticesCount = cell.template getSubentitiesCount< 0 >(); - cellSeed.setCornersCount( verticesCount ); for( LocalIndexType j = 0; j < verticesCount; j++ ) { - cellSeed.setCornerId( j, cell.template getSubentityIndex< 0 >( j ) ); + seed.setCornerId( j, cell.template getSubentityIndex< 0 >( j ) ); } } else { // Decompose non-planar cells @@ -124,7 +147,7 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) FaceMapArray faceMap( inFacesCount ); // Mapping of original face indeces to a group of decomposed face indices - // Find the number of points and faces in the outMesh and setup faceMap + // Count the number of points and faces in the outMesh and setup faceMap GlobalIndexType outPointsCount = inPointsCount; GlobalIndexType outFacesCount = 0; for( GlobalIndexType i = 0; i < inFacesCount; i++ ) { @@ -155,32 +178,40 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); } - // Set up cell seeds + // set cell corner counts for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { const auto cell = inMesh.template getEntity< 3 >( i ); const LocalIndexType cellFacesCount = cell.template getSubentitiesCount< 2 >(); - // Find the number of faces in the output cell - LocalIndexType cellSeedFacesCount = 0; + // Count the number of faces in the cell + LocalIndexType cornersCount = 0; for( LocalIndexType j = 0; j < cellFacesCount; j++ ) { const GlobalIndexType faceIdx = cell.template getSubentityIndex< 2 >( j ); const auto & faceMapping = faceMap[ faceIdx ]; - cellSeedFacesCount += faceMapping.second - faceMapping.first; + cornersCount += faceMapping.second - faceMapping.first; } - // Set up the cell seed - auto & cellSeed = meshBuilder.getCellSeed( i ); - cellSeed.setCornersCount( cellSeedFacesCount ); - for( LocalIndexType j = 0, faceSetIdx = 0; j < cellFacesCount; j++ ) { + meshBuilder.setCellCornersCount( i, cornersCount ); + } + + meshBuilder.initializeCellSeeds(); + + // Set cell corner ids + for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { + const auto cell = inMesh.template getEntity< 3 >( i ); + const LocalIndexType cellFacesCount = cell.template getSubentitiesCount< 2 >(); + + for( LocalIndexType j = 0, o = 0; j < cellFacesCount; j++ ) { const GlobalIndexType faceIdx = cell.template getSubentityIndex< 2 >( j ); const auto & faceMapping = faceMap[ faceIdx ]; + auto cellSeed = meshBuilder.getCellSeed( i ); for( GlobalIndexType k = faceMapping.first; k < faceMapping.second; k++ ) { - cellSeed.setCornerId( faceSetIdx++, k ); + cellSeed.setCornerId( o++, k ); } } } - // set corners count for face seeds + // set face corners count GlobalIndexType setFacesCount = 0; for( GlobalIndexType i = 0; i < inFacesCount; i++ ) { const auto & faceMapping = faceMap[ i ]; @@ -199,13 +230,13 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) meshBuilder.initializeFaceSeeds(); // Lambda for creating new points - auto createPointFunc = [&] ( const PointType & point ) { + auto createPointFunc = [&] ( const PointType& point ) { const auto pointIdx = setPointsCount++; meshBuilder.setPoint( pointIdx, point ); return pointIdx; }; - // Lambda for setting seed of decomposed triangle + // Lambda for setting corner ids of decomposed faces setFacesCount = 0; auto setDecomposedFaceFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { const GlobalIndexType faceId = setFacesCount++; diff --git a/src/TNL/Meshes/Mesh.h b/src/TNL/Meshes/Mesh.h index 8b04acbd4..2513982f3 100644 --- a/src/TNL/Meshes/Mesh.h +++ b/src/TNL/Meshes/Mesh.h @@ -51,7 +51,7 @@ class MeshInitializableBase // The points and cellSeeds arrays will be reset when not needed to save memory. void init( typename MeshTraitsType::PointArrayType& points, typename MeshTraitsType::FaceSeedMatrixType& faceSeeds, - typename MeshTraitsType::CellSeedArrayType& cellSeeds ); + typename MeshTraitsType::CellSeedMatrixType& cellSeeds ); }; // The mesh cannot be initialized on CUDA GPU, so this specialization is empty. diff --git a/src/TNL/Meshes/Mesh.hpp b/src/TNL/Meshes/Mesh.hpp index d23a33577..c928783f4 100644 --- a/src/TNL/Meshes/Mesh.hpp +++ b/src/TNL/Meshes/Mesh.hpp @@ -28,7 +28,7 @@ void MeshInitializableBase< MeshConfig, Device, MeshType >:: init( typename MeshTraitsType::PointArrayType& points, typename MeshTraitsType::FaceSeedMatrixType& faceSeeds, - typename MeshTraitsType::CellSeedArrayType& cellSeeds ) + typename MeshTraitsType::CellSeedMatrixType& cellSeeds ) { MeshType* mesh = static_cast< MeshType* >( this ); Initializer< typename MeshType::Config > initializer; diff --git a/src/TNL/Meshes/MeshBuilder.h b/src/TNL/Meshes/MeshBuilder.h index 626916975..303113a17 100644 --- a/src/TNL/Meshes/MeshBuilder.h +++ b/src/TNL/Meshes/MeshBuilder.h @@ -31,8 +31,8 @@ public: using LocalIndexType = typename MeshTraitsType::LocalIndexType; using PointType = typename MeshTraitsType::PointType; using CellTopology = typename MeshTraitsType::CellTopology; - using CellSeedType = typename MeshTraitsType::CellSeedType; using CellSeedMatrixType = typename MeshTraitsType::CellSeedMatrixType; + using CellSeedType = typename CellSeedMatrixType::EntitySeedMatrixSeed; using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; using FaceSeedType = typename FaceSeedMatrixType::EntitySeedMatrixSeed; @@ -60,7 +60,20 @@ public: void setCellsCount( const GlobalIndexType& cellsCount ) { - this->cellSeeds.setSize( cellsCount ); + if( getFacesCount() == 0 ) // faceSeeds aren't used ( cellSeeds store indeces of points ) + this->cellSeeds.setDimensions( cellsCount, getPointsCount() ); + else // faceSeeds are used ( cellSeeds store indeces of faces ) + this->cellSeeds.setDimensions( cellsCount, getFacesCount() ); + } + + void setCellCornersCount( const GlobalIndexType& cellIndex, const LocalIndexType& cornersCount ) + { + this->cellSeeds.setEntityCornersCount( cellIndex, cornersCount ); + } + + void initializeCellSeeds() + { + this->cellSeeds.initializeRows(); } GlobalIndexType getPointsCount() const @@ -75,7 +88,7 @@ public: GlobalIndexType getCellsCount() const { - return this->cellSeeds.getSize(); + return this->cellSeeds.getEntitiesCount(); } void setPoint( GlobalIndexType index, @@ -90,9 +103,9 @@ public: return this->faceSeeds.getSeed( index ); } - CellSeedType& getCellSeed( GlobalIndexType index ) + CellSeedType getCellSeed( GlobalIndexType index ) { - return this->cellSeeds[ index ]; + return this->cellSeeds.getSeed( index ); } bool build( MeshType& mesh ) @@ -105,8 +118,6 @@ public: private: using PointArrayType = typename MeshTraitsType::PointArrayType; - using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; - using FaceSeedArrayType = typename MeshTraitsType::FaceSeedArrayType; using BoolVector = Containers::Vector< bool, Devices::Host, GlobalIndexType >; bool validate() const @@ -123,11 +134,12 @@ private: if( faceSeeds.empty() ) { 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; + 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; } } @@ -143,11 +155,12 @@ private: for( GlobalIndexType i = 0; i < getFacesCount(); i++ ) { const auto faceSeed = this->faceSeeds.getSeed( i ); for( LocalIndexType j = 0; j < faceSeed.getCornersCount(); j++ ) { - if( faceSeed.getCornerId( j ) < 0 || getPointsCount() <= faceSeed.getCornerId( j ) ) { - std::cerr << "face seed " << i << " is referencing unavailable point " << faceSeed.getCornerId( j ) << std::endl; + 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[ faceSeed.getCornerId( j ) ] = true; + assignedPoints[ cornerId ] = true; } } @@ -161,13 +174,14 @@ private: assignedFaces.setValue( false ); for( GlobalIndexType i = 0; i < getCellsCount(); i++ ) { - const auto& cornerIds = this->cellSeeds[ i ].getCornerIds(); - for( LocalIndexType j = 0; j < cornerIds.getSize(); j++ ) { - if( cornerIds[ j ] < 0 || getFacesCount() <= cornerIds[ j ] ) { - std::cerr << "cell seed " << i << " is referencing unavailable face " << cornerIds[ j ] << std::endl; + 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[ cornerIds[ j ] ] = true; + assignedFaces[ cornerId ] = true; } } @@ -182,7 +196,7 @@ private: PointArrayType points; FaceSeedMatrixType faceSeeds; - CellSeedArrayType cellSeeds; + CellSeedMatrixType cellSeeds; BoolVector pointsSet; }; diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h index 358c1a18b..3ac007b72 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h @@ -50,13 +50,14 @@ class EntityInitializer DimensionTag< MeshTraits< MeshConfig >::meshDimension > >; 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 NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; - using SeedMatrixType = EntitySeedMatrix< MeshConfig, EntityTopology >; + using SeedMatrixType = typename EntityTraitsType::SeedMatrixType; public: static void initSubvertexMatrix( NeighborCountsArray& capacities, InitializerType& initializer ) @@ -64,19 +65,19 @@ public: initializer.template initSubentityMatrix< EntityTopology::dimension, 0 >( capacities ); } - static void initEntity( const GlobalIndexType entityIndex, const SeedType& entitySeed, InitializerType& initializer ) - { - // this is necessary if we want to use existing entities instead of intermediate seeds to create subentity seeds - for( LocalIndexType i = 0; i < entitySeed.getCornerIds().getSize(); i++ ) - initializer.template setSubentityIndex< EntityTopology::dimension, 0 >( entityIndex, i, entitySeed.getCornerIds()[ i ] ); - } - 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 ) + { + // this is necessary if we want to use existing entities instead of intermediate seeds to create subentity seeds + for( LocalIndexType i = 0; i < entitySeed.getCornerIds().getSize(); i++ ) + initializer.template setSubentityIndex< EntityTopology::dimension, 0 >( entityIndex, i, entitySeed.getCornerIds()[ i ] ); + } }; template< typename MeshConfig, @@ -87,13 +88,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 NeighborCountsArray& capacities, InitializerType& initializer ) {} + static void initSubvertexMatrix( SeedMatrixType& seeds, InitializerType& initializer ) {} static void initEntity( const GlobalIndexType entityIndex, const SeedType& entitySeed, InitializerType& initializer ) {} }; @@ -238,31 +242,25 @@ public: const GlobalIndexType subentitiesCount = mesh.template getEntitiesCount< SubdimensionTag::value >(); const GlobalIndexType superentitiesCount = mesh.template getEntitiesCount< SuperdimensionTag::value >(); - auto& cellSeeds = meshInitializer.getCellSeeds(); - - NeighborCountsArray capacities( cellSeeds.getSize() ); - - for( GlobalIndexType superentityIndex = 0; superentityIndex < capacities.getSize(); superentityIndex++ ) - capacities[ superentityIndex ] = cellSeeds[ superentityIndex ].getCornersCount(); - - 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 ); + auto& cellSeeds = meshInitializer.getCellSeeds(); for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { - auto& cellSeed = cellSeeds[ superentityIndex ]; + const auto cellSeed = cellSeeds.getSeed( superentityIndex ); for( LocalIndexType i = 0; i < cellSeed.getCornersCount(); i++ ) { - const GlobalIndexType subentityIndex = cellSeed.getCornerIds()[ i ]; - meshInitializer.template setSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i, subentityIndex ); + const GlobalIndexType subentityIndex = cellSeed.getCornerId( i ); superentitiesCounts[ subentityIndex ]++; } } - cellSeeds.reset(); + + 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 >(); @@ -395,30 +393,10 @@ 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 >(); - auto& cellSeeds = meshInitializer.getCellSeeds(); - - NeighborCountsArray capacities( cellSeeds.getSize() ); - - for( GlobalIndexType superentityIndex = 0; superentityIndex < capacities.getSize(); superentityIndex++ ) - capacities[ superentityIndex ] = cellSeeds[ superentityIndex ].getCornersCount(); - - meshInitializer.template initSubentityMatrix< SuperdimensionTag::value, SubdimensionTag::value >( capacities, subentitiesCount ); - - for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) - { - auto& cellSeed = cellSeeds[ superentityIndex ]; - for( LocalIndexType i = 0; i < cellSeed.getCornersCount(); i++ ) - { - const GlobalIndexType subentityIndex = cellSeed.getCornerIds()[ i ]; - meshInitializer.template setSubentityIndex< SuperdimensionTag::value, SubdimensionTag::value >( superentityIndex, i, subentityIndex ); - } - } - cellSeeds.reset(); - + 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 ); } }; diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h index 3e9781d2b..0d9460ea9 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h @@ -28,8 +28,6 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, false > using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; - static constexpr int cornersCount = SubentityTraitsType::count; - class EntitySeedMatrixSeed { using RowView = typename SubentityMatrixType::RowView; @@ -41,7 +39,7 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, false > static constexpr LocalIndexType getCornersCount() { - return cornersCount; + return SubentityTraitsType::count; } void setCornerId( const LocalIndexType& cornerIndex, const GlobalIndexType& pointIndex ) @@ -72,7 +70,7 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, false > static constexpr LocalIndexType getCornersCount() { - return cornersCount; + return SubentityTraitsType::count; } GlobalIndexType getCornerId( const LocalIndexType& cornerIndex ) const @@ -89,7 +87,7 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, false > matrix.setDimensions( entitiesCount, pointsCount ); NeighborCountsArray capacities( entitiesCount ); - capacities.setValue( cornersCount ); + capacities.setValue( SubentityTraitsType::count ); matrix.setRowCapacities( capacities ); } @@ -106,24 +104,137 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, false > matrix.reset(); } - void setSeedIndex( const GlobalIndexType& entityIndex, const LocalIndexType& localIndex, const GlobalIndexType& globalIndex ) + GlobalIndexType getEntitiesCount() const { - matrix.getRow( entityIndex ).setElement( localIndex, globalIndex, true ); + return matrix.getRows(); } - GlobalIndexType getEntitiesCount() const + SubentityMatrixType& getMatrix() { - return matrix.getRows(); + 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; + + 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 ); } - constexpr LocalIndexType getEntityCornersCount( const GlobalIndexType& entityIndex ) const + // This method is only here for compatibility with specialization for dynamic entity topologies + void setEntityCornersCount( const GlobalIndexType& entityIndex, const LocalIndexType& count ) + {} + + // This method is only here for compatibility with specialization for dynamic entity topologies + void initializeRows() + {} + + void reset() { - return cornersCount; + matrix.reset(); } - GlobalIndexType getSeedIndex( const GlobalIndexType& entityIndex, const LocalIndexType& localIndex ) const + GlobalIndexType getEntitiesCount() const { - return matrix.getRow( entityIndex ).getColumnIndex( localIndex ); + return matrix.getRows(); } SubentityMatrixType& getMatrix() @@ -139,7 +250,7 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, false > NeighborCountsArray getEntityCornerCounts() const { NeighborCountsArray counts( getEntitiesCount() ); - counts.setValue( cornersCount ); + counts.setValue( 1 ); return counts; } @@ -254,26 +365,11 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, true > counts.reset(); } - void setSeedIndex( const GlobalIndexType& entityIndex, const LocalIndexType& localIndex, const GlobalIndexType& globalIndex ) - { - matrix.getRow( entityIndex ).setElement( localIndex, globalIndex, true ); - } - GlobalIndexType getEntitiesCount() const { return matrix.getRows(); } - LocalIndexType getEntityCornersCount( const GlobalIndexType& entityIndex ) const - { - return counts.getElement( entityIndex ); - } - - GlobalIndexType getSeedIndex( const GlobalIndexType& entityIndex, const LocalIndexType& localIndex ) const - { - return matrix.getRow( entityIndex ).getColumnIndex( localIndex ); - } - SubentityMatrixType& getMatrix() { return matrix; diff --git a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index ef840d2b8..aefbe2f72 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -77,7 +77,7 @@ class Initializer 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; @@ -89,7 +89,7 @@ class Initializer // The points and cellSeeds arrays will be reset when not needed to save memory. void createMesh( PointArrayType& points, FaceSeedMatrixType& faceSeeds, - CellSeedArrayType& cellSeeds, + CellSeedMatrixType& cellSeeds, MeshType& mesh ) { // copy points @@ -178,12 +178,12 @@ class Initializer return mesh->template getSuperentitiesMatrix< Dimension, Superdimension >(); } - CellSeedArrayType& getCellSeeds() + CellSeedMatrixType& getCellSeeds() { return *(this->cellSeeds); } protected: - CellSeedArrayType* cellSeeds = nullptr; + CellSeedMatrixType* cellSeeds = nullptr; }; /**** @@ -207,35 +207,24 @@ protected: 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() ); - - NeighborCountsArray capacities( cellSeeds.getSize() ); - - for( GlobalIndexType i = 0; i < capacities.getSize(); i++ ) - capacities[ i ] = cellSeeds[ i ].getCornersCount(); - - EntityInitializerType::initSubvertexMatrix( capacities, initializer ); - - 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().getSize() ); + initializer.template setEntitiesCount< DimensionTag::value >( initializer.getCellSeeds().getEntitiesCount() ); BaseType::initEntities( initializer, faceSeeds, mesh ); } @@ -265,8 +254,7 @@ protected: using EntityInitializerType = EntityInitializer< MeshConfig, EntityTopology >; using SeedType = EntitySeed< MeshConfig, EntityTopology >; using SeedIndexedSet = typename MeshTraits< MeshConfig >::template EntityTraits< DimensionTag::value >::SeedIndexedSetType; - using CellSeedArrayType = typename MeshTraitsType::CellSeedArrayType; - using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; + using SeedMatrixType = typename EntityTraitsType::SeedMatrixType; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; public: @@ -321,19 +309,13 @@ protected: BaseType::initEntities( initializer, mesh ); } - void initEntities( InitializerType& initializer, FaceSeedMatrixType& faceSeeds, MeshType& mesh ) + void initEntities( InitializerType& initializer, SeedMatrixType& seeds, MeshType& mesh ) { //std::cout << " Initiating entities with dimension " << DimensionTag::value << " ... " << std::endl; - - initializer.template setEntitiesCount< DimensionTag::value >( faceSeeds.getEntitiesCount() ); - - EntityInitializerType::initSubvertexMatrix( faceSeeds, initializer ); - - // initialize links between the entities and all superentities - EntityInitializerType::initSuperentities( initializer, mesh ); - - // continue with the next dimension - BaseType::initEntities( initializer, mesh ); + 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: @@ -358,7 +340,7 @@ class InitializerLayer< MeshConfig, DimensionTag< 0 > > using InitializerType = Initializer< MeshConfig >; using EntityInitializerType = EntityInitializer< MeshConfig, EntityTopology >; using SeedType = EntitySeed< MeshConfig, EntityTopology >; - using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; + using SeedMatrixType = typename EntityTraitsType::SeedMatrixType; public: @@ -374,7 +356,7 @@ class InitializerLayer< MeshConfig, DimensionTag< 0 > > } // This overload is only here for compatibility with Polyhedrons, it is never called - void initEntities( InitializerType& initializer, FaceSeedMatrixType& faceSeeds, MeshType& mesh ) + void initEntities( InitializerType& initializer, SeedMatrixType& faceSeeds, MeshType& mesh ) { } }; diff --git a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h index 641e96110..b0c531ba9 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h +++ b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h @@ -267,15 +267,15 @@ public: static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { const auto& cellSeeds = initializer.getCellSeeds(); - const auto& faces = cellSeeds[ entityIndex ].getCornerIds(); + const auto faces = cellSeeds.getSeed( entityIndex ); SubentitySeedArray seeds; - seeds.setSize( faces.getSize() ); + seeds.setSize( faces.getCornersCount() ); for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) { SubentitySeed& seed = seeds[ i ]; - GlobalIndexType faceIdx = faces[ i ]; + GlobalIndexType faceIdx = faces.getCornerId( i ); const auto& subvertices = mesh.template getSubentitiesMatrix< 2, 0 >().getRow( faceIdx ); const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< 2, 0 >( faceIdx ); seed.setCornersCount( subverticesCount ); @@ -292,11 +292,11 @@ public: static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) { const auto& cellSeeds = initializer.getCellSeeds(); - const auto& faces = cellSeeds[ entityIndex ].getCornerIds(); + const auto faces = cellSeeds.getSeed( entityIndex ); - for( LocalIndexType i = 0; i < faces.getSize(); i++ ) + for( LocalIndexType i = 0; i < faces.getCornersCount(); i++ ) { - GlobalIndexType faceIdx = faces[ i ]; + GlobalIndexType faceIdx = faces.getCornerId( i ); const auto& subvertices = mesh.template getSubentitiesMatrix< 2, 0 >().getRow( faceIdx ); const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< 2, 0 >( faceIdx ); SubentitySeed seed; @@ -310,8 +310,8 @@ public: static LocalIndexType getSubentitiesCount( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { - auto& cellSeeds = initializer.getCellSeeds(); - return cellSeeds[ entityIndex ].getCornersCount(); + const auto& cellSeeds = initializer.getCellSeeds(); + return cellSeeds.getSeed( entityIndex ).getCornersCount(); } }; diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h index f2c4c8d58..cc7fbe4f2 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h @@ -51,6 +51,7 @@ public: 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 >; @@ -78,6 +79,7 @@ public: 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 >; diff --git a/src/TNL/Meshes/Readers/MeshReader.h b/src/TNL/Meshes/Readers/MeshReader.h index ee23cb35b..c52f65d4c 100644 --- a/src/TNL/Meshes/Readers/MeshReader.h +++ b/src/TNL/Meshes/Readers/MeshReader.h @@ -208,7 +208,7 @@ public: offsetStart = 0; for( std::size_t i = 0; i < NumberOfFaces; i++ ) { - auto seed = meshBuilder.getFaceSeed( 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 ] ); @@ -223,11 +223,19 @@ public: // let's just assume that the connectivity and offsets arrays have the same type... using mpark::get; const auto& offsets = get< std::decay_t >( cellOffsetsArray ); + 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 ]; - seed.setCornersCount( offsetEnd - offsetStart ); + meshBuilder.setCellCornersCount( i, offsetEnd - offsetStart ); + offsetStart = offsetEnd; + } + meshBuilder.initializeCellSeeds(); + + 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; diff --git a/src/UnitTests/Meshes/MeshGeometryTest.h b/src/UnitTests/Meshes/MeshGeometryTest.h index a87932b9c..df02b42a5 100644 --- a/src/UnitTests/Meshes/MeshGeometryTest.h +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -90,8 +90,9 @@ TEST( MeshGeometryTest, Polygon2DAreaTest ) meshBuilder.setPoint( 4, point4 ); meshBuilder.setCellsCount( 1 ); + meshBuilder.setCellCornersCount( 0, 5 ); + meshBuilder.initializeCellSeeds(); - meshBuilder.getCellSeed( 0 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -139,7 +140,9 @@ TEST( MeshGeometryTest, Polygon3DAreaTest ) meshBuilder.setPoint( 4, point4 ); meshBuilder.setCellsCount( 1 ); - meshBuilder.getCellSeed( 0 ).setCornersCount( 5 ); + meshBuilder.setCellCornersCount( 0, 5 ); + meshBuilder.initializeCellSeeds(); + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -319,7 +322,9 @@ TEST( MeshGeometryTest, PolyhedronAreaTest ) meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 8 ); meshBuilder.setCellsCount( 1 ); - meshBuilder.getCellSeed( 0 ).setCornersCount( 9 ); + meshBuilder.setCellCornersCount( 0, 9 ); + meshBuilder.initializeCellSeeds(); + meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -386,9 +391,15 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) meshBuilder.setPoint( 9, point4_ ); meshBuilder.setCellsCount( 6 ); + meshBuilder.setCellCornersCount( 0, 5 ); + meshBuilder.setCellCornersCount( 1, 5 ); + meshBuilder.setCellCornersCount( 2, 5 ); + meshBuilder.setCellCornersCount( 3, 5 ); + meshBuilder.setCellCornersCount( 4, 5 ); + meshBuilder.setCellCornersCount( 5, 5 ); + meshBuilder.initializeCellSeeds(); // Planar cell with non-deviated points - meshBuilder.getCellSeed( 0 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -396,7 +407,6 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) meshBuilder.getCellSeed( 0 ).setCornerId( 4, 4 ); // Non-Planar cell with 0th point deviated - meshBuilder.getCellSeed( 1 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 1 ).setCornerId( 0, 5 ); meshBuilder.getCellSeed( 1 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 1 ).setCornerId( 2, 2 ); @@ -404,7 +414,6 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) meshBuilder.getCellSeed( 1 ).setCornerId( 4, 4 ); // Non-Planar cell with 1th point deviated - meshBuilder.getCellSeed( 2 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 2 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 2 ).setCornerId( 1, 6 ); meshBuilder.getCellSeed( 2 ).setCornerId( 2, 2 ); @@ -412,7 +421,6 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) meshBuilder.getCellSeed( 2 ).setCornerId( 4, 4 ); // Non-Planar cell with 2th point deviated - meshBuilder.getCellSeed( 3 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 3 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 3 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 3 ).setCornerId( 2, 7 ); @@ -420,7 +428,6 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) meshBuilder.getCellSeed( 3 ).setCornerId( 4, 4 ); // Non-Planar cell with 3th point deviated - meshBuilder.getCellSeed( 4 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 4 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 4 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 4 ).setCornerId( 2, 2 ); @@ -428,7 +435,6 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) meshBuilder.getCellSeed( 4 ).setCornerId( 4, 4 ); // Non-Planar cell with 4th point deviated - meshBuilder.getCellSeed( 5 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 5 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 5 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 5 ).setCornerId( 2, 2 ); @@ -486,9 +492,16 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) */ meshBuilder.setCellsCount( 7 ); + meshBuilder.setCellCornersCount( 0, 6 ); + meshBuilder.setCellCornersCount( 1, 5 ); + meshBuilder.setCellCornersCount( 2, 4 ); + meshBuilder.setCellCornersCount( 3, 4 ); + meshBuilder.setCellCornersCount( 4, 5 ); + meshBuilder.setCellCornersCount( 5, 5 ); + meshBuilder.setCellCornersCount( 6, 5 ); + meshBuilder.initializeCellSeeds(); // 1 0 3 2 4 5 - meshBuilder.getCellSeed( 0 ).setCornersCount( 6 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 3 ); @@ -497,7 +510,6 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); // 8 7 0 1 6 - meshBuilder.getCellSeed( 1 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 1 ).setCornerId( 0, 8 ); meshBuilder.getCellSeed( 1 ).setCornerId( 1, 7 ); meshBuilder.getCellSeed( 1 ).setCornerId( 2, 0 ); @@ -505,21 +517,18 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) meshBuilder.getCellSeed( 1 ).setCornerId( 4, 6 ); // 9 3 0 7 - meshBuilder.getCellSeed( 2 ).setCornersCount( 4 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 4 ).setCornerId( 0, 12 ); meshBuilder.getCellSeed( 4 ).setCornerId( 1, 11 ); meshBuilder.getCellSeed( 4 ).setCornerId( 2, 2 ); @@ -527,7 +536,6 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) meshBuilder.getCellSeed( 4 ).setCornerId( 4, 9 ); // 13 4 2 11 14 - meshBuilder.getCellSeed( 5 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 5 ).setCornerId( 0, 13 ); meshBuilder.getCellSeed( 5 ).setCornerId( 1, 4 ); meshBuilder.getCellSeed( 5 ).setCornerId( 2, 2 ); @@ -535,7 +543,6 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) meshBuilder.getCellSeed( 5 ).setCornerId( 4, 14 ); // 10 5 4 13 15 - meshBuilder.getCellSeed( 6 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 6 ).setCornerId( 0, 10 ); meshBuilder.getCellSeed( 6 ).setCornerId( 1, 5 ); meshBuilder.getCellSeed( 6 ).setCornerId( 2, 4 ); @@ -786,9 +793,11 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) */ meshBuilder.setCellsCount( 2 ); + meshBuilder.setCellCornersCount( 0, 9 ); + meshBuilder.setCellCornersCount( 1, 8 ); + meshBuilder.initializeCellSeeds(); // 0 1 2 3 4 5 6 7 8 - meshBuilder.getCellSeed( 0 ).setCornersCount( 9 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -800,7 +809,6 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) meshBuilder.getCellSeed( 0 ).setCornerId( 8, 8 ); // 9 10 11 12 13 5 14 15 - meshBuilder.getCellSeed( 1 ).setCornersCount( 8 ); meshBuilder.getCellSeed( 1 ).setCornerId( 0, 9 ); meshBuilder.getCellSeed( 1 ).setCornerId( 1, 10 ); meshBuilder.getCellSeed( 1 ).setCornerId( 2, 11 ); @@ -887,15 +895,16 @@ TEST( MeshGeometryTest, Polygon3DGetPlanarMeshTest ) meshBuilder.setPoint( 5, point5 ); meshBuilder.setCellsCount( 2 ); + meshBuilder.setCellCornersCount( 0, 4 ); + meshBuilder.setCellCornersCount( 1, 4 ); + meshBuilder.initializeCellSeeds(); // Planar cell - meshBuilder.getCellSeed( 0 ).setCornersCount( 4 ); 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 ).setCornersCount( 4 ); meshBuilder.getCellSeed( 1 ).setCornerId( 0, 1 ); meshBuilder.getCellSeed( 1 ).setCornerId( 1, 4 ); meshBuilder.getCellSeed( 1 ).setCornerId( 2, 5 ); @@ -1145,9 +1154,11 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) */ meshBuilder.setCellsCount( 2 ); + meshBuilder.setCellCornersCount( 0, 9 ); + meshBuilder.setCellCornersCount( 1, 8 ); + meshBuilder.initializeCellSeeds(); // 0 1 2 3 4 5 6 7 8 - meshBuilder.getCellSeed( 0 ).setCornersCount( 9 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -1159,7 +1170,6 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) meshBuilder.getCellSeed( 0 ).setCornerId( 8, 8 ); // 9 10 11 12 13 5 14 15 - meshBuilder.getCellSeed( 1 ).setCornersCount( 8 ); meshBuilder.getCellSeed( 1 ).setCornerId( 0, 9 ); meshBuilder.getCellSeed( 1 ).setCornerId( 1, 10 ); meshBuilder.getCellSeed( 1 ).setCornerId( 2, 11 ); diff --git a/src/UnitTests/Meshes/MeshTest.h b/src/UnitTests/Meshes/MeshTest.h index 4ba992bf0..96b2c3d69 100644 --- a/src/UnitTests/Meshes/MeshTest.h +++ b/src/UnitTests/Meshes/MeshTest.h @@ -1067,14 +1067,15 @@ TEST( MeshTest, TwoPolygonsTest ) meshBuilder.setPoint( 4, point4 ); meshBuilder.setCellsCount( 2 ); + meshBuilder.setCellCornersCount( 0, 4 ); + meshBuilder.setCellCornersCount( 1, 3 ); + meshBuilder.initializeCellSeeds(); - meshBuilder.getCellSeed( 0 ).setCornersCount( 4 ); 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 ).setCornersCount( 3 ); meshBuilder.getCellSeed( 1 ).setCornerId( 0, 3 ); meshBuilder.getCellSeed( 1 ).setCornerId( 1, 2 ); meshBuilder.getCellSeed( 1 ).setCornerId( 2, 4 ); @@ -1244,8 +1245,18 @@ TEST( MeshTest, SevenPolygonsTest ) meshBuilder.setCellsCount( 7 ); + meshBuilder.setCellsCount( 7 ); + meshBuilder.setCellCornersCount( 0, 6 ); + meshBuilder.setCellCornersCount( 1, 5 ); + meshBuilder.setCellCornersCount( 2, 4 ); + meshBuilder.setCellCornersCount( 3, 4 ); + meshBuilder.setCellCornersCount( 4, 5 ); + meshBuilder.setCellCornersCount( 5, 5 ); + meshBuilder.setCellCornersCount( 6, 5 ); + meshBuilder.initializeCellSeeds(); + + // 1 0 3 2 4 5 - meshBuilder.getCellSeed( 0 ).setCornersCount( 6 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 3 ); @@ -1254,7 +1265,6 @@ TEST( MeshTest, SevenPolygonsTest ) meshBuilder.getCellSeed( 0 ).setCornerId( 5, 5 ); // 8 7 0 1 6 - meshBuilder.getCellSeed( 1 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 1 ).setCornerId( 0, 8 ); meshBuilder.getCellSeed( 1 ).setCornerId( 1, 7 ); meshBuilder.getCellSeed( 1 ).setCornerId( 2, 0 ); @@ -1262,21 +1272,18 @@ TEST( MeshTest, SevenPolygonsTest ) meshBuilder.getCellSeed( 1 ).setCornerId( 4, 6 ); // 9 3 0 7 - meshBuilder.getCellSeed( 2 ).setCornersCount( 4 ); 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 ).setCornersCount( 4 ); 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 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 4 ).setCornerId( 0, 12 ); meshBuilder.getCellSeed( 4 ).setCornerId( 1, 11 ); meshBuilder.getCellSeed( 4 ).setCornerId( 2, 2 ); @@ -1284,7 +1291,6 @@ TEST( MeshTest, SevenPolygonsTest ) meshBuilder.getCellSeed( 4 ).setCornerId( 4, 9 ); // 13 4 2 11 14 - meshBuilder.getCellSeed( 5 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 5 ).setCornerId( 0, 13 ); meshBuilder.getCellSeed( 5 ).setCornerId( 1, 4 ); meshBuilder.getCellSeed( 5 ).setCornerId( 2, 2 ); @@ -1292,7 +1298,6 @@ TEST( MeshTest, SevenPolygonsTest ) meshBuilder.getCellSeed( 5 ).setCornerId( 4, 14 ); // 10 5 4 13 15 - meshBuilder.getCellSeed( 6 ).setCornersCount( 5 ); meshBuilder.getCellSeed( 6 ).setCornerId( 0, 10 ); meshBuilder.getCellSeed( 6 ).setCornerId( 1, 5 ); meshBuilder.getCellSeed( 6 ).setCornerId( 2, 4 ); @@ -2775,9 +2780,11 @@ TEST( MeshTest, TwoPolyhedronsTest ) */ meshBuilder.setCellsCount( 2 ); + meshBuilder.setCellCornersCount( 0, 9 ); + meshBuilder.setCellCornersCount( 1, 8 ); + meshBuilder.initializeCellSeeds(); // 0 1 2 3 4 5 6 7 8 - meshBuilder.getCellSeed( 0 ).setCornersCount( 9 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -2789,7 +2796,6 @@ TEST( MeshTest, TwoPolyhedronsTest ) meshBuilder.getCellSeed( 0 ).setCornerId( 8, 8 ); // 9 10 11 12 13 5 14 15 - meshBuilder.getCellSeed( 1 ).setCornersCount( 8 ); meshBuilder.getCellSeed( 1 ).setCornerId( 0, 9 ); meshBuilder.getCellSeed( 1 ).setCornerId( 1, 10 ); meshBuilder.getCellSeed( 1 ).setCornerId( 2, 11 ); -- GitLab From c9b50715a50abfb5512e2a5bc724e745503cf6af Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Mon, 6 Sep 2021 17:46:20 +0200 Subject: [PATCH 26/42] Added unit test for FPMAReader and polygonal mesh test in VTKReaderTest and VTUReaderTest --- src/UnitTests/Meshes/CMakeLists.txt | 2 +- src/UnitTests/Meshes/FPMAReaderTest.cpp | 51 +++ src/UnitTests/Meshes/VTKReaderTest.cpp | 19 + src/UnitTests/Meshes/VTUReaderTest.cpp | 19 + .../Meshes/data/polygons/unicorn.vtk | 384 ++++++++++++++++++ .../Meshes/data/polygons/unicorn.vtu | 23 ++ .../polyhedrons/Poly_simple_corrected.fpma | 37 ++ 7 files changed, 534 insertions(+), 1 deletion(-) create mode 100644 src/UnitTests/Meshes/FPMAReaderTest.cpp create mode 100644 src/UnitTests/Meshes/data/polygons/unicorn.vtk create mode 100644 src/UnitTests/Meshes/data/polygons/unicorn.vtu create mode 100644 src/UnitTests/Meshes/data/polyhedrons/Poly_simple_corrected.fpma diff --git a/src/UnitTests/Meshes/CMakeLists.txt b/src/UnitTests/Meshes/CMakeLists.txt index 7ffed3066..c8e71e955 100644 --- a/src/UnitTests/Meshes/CMakeLists.txt +++ b/src/UnitTests/Meshes/CMakeLists.txt @@ -59,7 +59,7 @@ 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/FPMAReaderTest.cpp b/src/UnitTests/Meshes/FPMAReaderTest.cpp new file mode 100644 index 000000000..19aca53d2 --- /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/Poly_simple_corrected.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, 22 ); + EXPECT_EQ( faces, 16 ); + EXPECT_EQ( cells, 2 ); + + 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/VTKReaderTest.cpp b/src/UnitTests/Meshes/VTKReaderTest.cpp index 5bb27c590..9d2df309b 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 d3d4391e8..9a37f765d 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 000000000..82753c4bc --- /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 000000000..51890a985 --- /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/Poly_simple_corrected.fpma b/src/UnitTests/Meshes/data/polyhedrons/Poly_simple_corrected.fpma new file mode 100644 index 000000000..ccd2ad753 --- /dev/null +++ b/src/UnitTests/Meshes/data/polyhedrons/Poly_simple_corrected.fpma @@ -0,0 +1,37 @@ +# 22: number of vertices +22 +# vertex coordinates (x,y,z)-order +-1.25 1.1665 1.203 -1.20683 1.16951 1.20537 -1.16843 1.19337 1.17878 -1.21025 1.21901 1.15383 -1.25 1.2128 1.1567 -1.20816 1.25 1.16756 -1.25 1.25 1.18056 -1.14802 1.21553 1.21165 -1.16186 1.25 1.21385 -1.20307 1.17486 1.25 -1.25 1.18056 1.25 -1.15677 1.22115 1.25 -1.18056 1.25 1.25 -1.25 1.25 1.25 -1.09277 1.20806 1.19263 -1.07219 1.22167 1.17994 -1.07215 1.25 1.18679 -1.05697 1.21124 1.19697 -1.04607 1.21508 1.22076 -1.0214 1.25 1.22293 -1.06418 1.22115 1.25 -1.04167 1.25 1.25 +# 16: number of faces +16 +# the first number means the number of vertices and the rest of numbers in the same line is vertex indicies attached to the face +5 0 1 2 3 4 +4 4 3 5 6 +5 5 3 2 7 8 +4 9 1 0 10 +5 11 7 2 1 9 +4 8 7 11 12 +5 13 12 11 9 10 +5 13 10 0 4 6 +5 13 6 5 8 12 +5 8 7 14 15 16 +5 16 15 17 18 19 +6 20 18 17 14 7 11 +3 17 15 14 +4 21 19 18 20 +4 21 20 11 12 +5 12 8 16 19 21 +# 2: number of cells +2 +# the first number means the number of faces and the rest of numbers in the same line are face indicies attached to the cell +9 0 1 2 3 4 5 6 7 8 +8 9 10 11 12 13 5 14 15 +# Additional information only, does contain topology information +# 1: The number of special selections, here there is only one selection named by boudary_face +1 +# boundary_face" is the name +boundary_face +# "3" means a boundary and "5" means 5 faces, and the last line is the face indices. You can see these faces in the figure, surrounded by green edges. +3 +5 +6 7 8 14 15 -- GitLab From 1770eec4839e6c732df7f3ec11ef0e36d533270a Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Tue, 7 Sep 2021 10:04:51 +0200 Subject: [PATCH 27/42] Refactored getDecomposedMesh function to use ParallelFor --- src/Benchmarks/Mesh/MeshBenchmarks.h | 4 +- src/TNL/Assert.h | 7 + src/TNL/Meshes/Geometry/EntityDecomposer.h | 76 +++---- src/TNL/Meshes/Geometry/getDecomposedMesh.h | 229 ++++++++++++-------- 4 files changed, 191 insertions(+), 125 deletions(-) diff --git a/src/Benchmarks/Mesh/MeshBenchmarks.h b/src/Benchmarks/Mesh/MeshBenchmarks.h index ce267ea5f..a1daac4a6 100644 --- a/src/Benchmarks/Mesh/MeshBenchmarks.h +++ b/src/Benchmarks/Mesh/MeshBenchmarks.h @@ -341,7 +341,7 @@ struct MeshBenchmarks static void benchmark_decomposition( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { auto benchmark_func = [&] () { - const auto decomposedMesh = getDecomposedMesh< DecomposerVersion >( mesh_src ); + auto meshBuilder = decomposeMesh< DecomposerVersion >( mesh_src ); }; benchmark.time< Devices::Host >( "CPU", @@ -356,7 +356,7 @@ struct MeshBenchmarks static void benchmark_decomposition( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { auto benchmark_func = [&] () { - const auto decomposedMesh = getDecomposedMesh< DecomposerVersion, SubDecomposerVersion >( mesh_src ); + auto meshBuilder = decomposeMesh< DecomposerVersion, SubDecomposerVersion >( mesh_src ); }; benchmark.time< Devices::Host >( "CPU", diff --git a/src/TNL/Assert.h b/src/TNL/Assert.h index 99f833d24..06b68e33c 100644 --- a/src/TNL/Assert.h +++ b/src/TNL/Assert.h @@ -217,6 +217,13 @@ fatalFailure() #endif } +template< typename T > +::std::stringstream& operator<<( ::std::stringstream& ss, const std::pair< T, T >& pair ) +{ + ss << '(' << pair.first << ',' << pair.second << ')'; + return ss; +} + template< typename T > struct Formatter { diff --git a/src/TNL/Meshes/Geometry/EntityDecomposer.h b/src/TNL/Meshes/Geometry/EntityDecomposer.h index 89e995d8f..d15662ff8 100644 --- a/src/TNL/Meshes/Geometry/EntityDecomposer.h +++ b/src/TNL/Meshes/Geometry/EntityDecomposer.h @@ -34,10 +34,8 @@ struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersio using PointType = typename VertexMeshEntityType::PointType; using GlobalIndexType = typename MeshConfig::GlobalIndexType; using LocalIndexType = typename MeshConfig::LocalIndexType; - using PointCreationFunctorType = std::function< GlobalIndexType ( const PointType& ) >; - using DecomposedEntityFunctorType = std::function< void ( GlobalIndexType, GlobalIndexType, GlobalIndexType ) >; - static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType & entity ) + static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType& entity ) { const auto pointsCount = entity.template getSubentitiesCount< 0 >(); if( pointsCount == 3 ) // polygon is triangle @@ -45,29 +43,31 @@ struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersio return { 1, pointsCount }; // 1 extra centroid point and decomposition creates pointsCount triangles } - static void decompose( const MeshEntityType & entity, - PointCreationFunctorType pointCreationFunctor, - DecomposedEntityFunctorType decomposedEntityFunctor ) + 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 ); - decomposedEntityFunctor( v0, v1, v2 ); + addCell( v0, v1, v2 ); } else { // polygon is decomposed as it has got more than 3 vertices - const auto v0 = pointCreationFunctor( getEntityCenter( entity.getMesh(), entity ) ); + 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 ); - decomposedEntityFunctor( v0, v1, v2 ); + addCell( v0, v1, v2 ); } { // wrap around term const auto v1 = entity.template getSubentityIndex< 0 >( verticesCount - 1 ); const auto v2 = entity.template getSubentityIndex< 0 >( 0 ); - decomposedEntityFunctor( v0, v1, v2 ); + addCell( v0, v1, v2 ); } } } @@ -83,18 +83,18 @@ struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersio using PointType = typename VertexMeshEntityType::PointType; using GlobalIndexType = typename MeshConfig::GlobalIndexType; using LocalIndexType = typename MeshConfig::LocalIndexType; - using PointCreationFunctorType = std::function< GlobalIndexType ( const PointType& ) >; - using DecomposedEntityFunctorType = std::function< void ( GlobalIndexType, GlobalIndexType, GlobalIndexType ) >; - static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType & entity ) + 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) } - static void decompose( const MeshEntityType & entity, - PointCreationFunctorType pointCreationFunctor, - DecomposedEntityFunctorType decomposedEntityFunctor ) + 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 >(); @@ -102,7 +102,7 @@ struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersio 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 ); - decomposedEntityFunctor( v0, v1, v2 ); + addCell( v0, v1, v2 ); } } }; @@ -119,11 +119,9 @@ struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVer using PointType = typename VertexMeshEntityType::PointType; using GlobalIndexType = typename MeshConfig::GlobalIndexType; using LocalIndexType = typename MeshConfig::LocalIndexType; - using PointCreationFunctorType = std::function< GlobalIndexType ( const PointType& ) >; - using DecomposedEntityFunctorType = std::function< void ( GlobalIndexType, GlobalIndexType, GlobalIndexType, GlobalIndexType ) >; using SubentityDecomposer = EntityDecomposer< MeshConfig, FaceTopology, SubentityDecomposerVersion >; - static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType & entity ) + static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType& entity ) { const auto& mesh = entity.getMesh(); GlobalIndexType extraPointsCount = 1, // there is one new centroid point @@ -140,22 +138,24 @@ struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVer return { extraPointsCount, entitiesCount }; } + template< typename AddPointFunctor, + typename AddCellFunctor > static void decompose( const MeshEntityType & entity, - PointCreationFunctorType pointCreationFunctor, - DecomposedEntityFunctorType decomposedEntityFunctor ) + AddPointFunctor&& addPoint, + AddCellFunctor&& addCell ) { - const auto & mesh = entity.getMesh(); - const auto v3 = pointCreationFunctor( getEntityCenter( mesh, entity ) ); + const auto& mesh = entity.getMesh(); + const auto v3 = addPoint( getEntityCenter( mesh, entity ) ); // Lambda for creating tetrahedron from decomposed triangles of faces - auto decomposedSubentityFunctor = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { - decomposedEntityFunctor( v0, v1, v2, v3 ); + 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, pointCreationFunctor, decomposedSubentityFunctor ); + SubentityDecomposer::decompose( face, std::forward< AddPointFunctor >( addPoint ), addFace ); } } }; @@ -174,11 +174,9 @@ struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVer using GlobalIndexType = typename MeshConfig::GlobalIndexType; using LocalIndexType = typename MeshConfig::LocalIndexType; using RealType = typename MeshConfig::RealType; - using PointCreationFunctorType = std::function< GlobalIndexType ( const PointType& ) >; - using DecomposedEntityFunctorType = std::function< void ( GlobalIndexType, GlobalIndexType, GlobalIndexType, GlobalIndexType ) >; using SubentityDecomposer = EntityDecomposer< MeshConfig, FaceTopology, SubentityDecomposerVersion >; - static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType & entity ) + static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType& entity ) { const auto& mesh = entity.getMesh(); const auto v3 = entity.template getSubentityIndex< 0 >( 0 ); @@ -197,29 +195,31 @@ struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVer return { extraPointsCount, entitiesCount }; } - static void decompose( const MeshEntityType & entity, - PointCreationFunctorType pointCreationFunctor, - DecomposedEntityFunctorType decomposedEntityFunctor ) + template< typename AddPointFunctor, + typename AddCellFunctor > + static void decompose( const MeshEntityType& entity, + AddPointFunctor&& addPoint, + AddCellFunctor&& addCell ) { - const auto & mesh = entity.getMesh(); + 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 decomposedSubentityFunctor = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { - decomposedEntityFunctor( v0, v1, v2, v3 ); + 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, pointCreationFunctor, decomposedSubentityFunctor ); + SubentityDecomposer::decompose( face, std::forward< AddPointFunctor >( addPoint ), addFace ); } } } private: - static bool faceContainsPoint( const MeshSubentityType & face, const GlobalIndexType point ) + static bool faceContainsPoint( const MeshSubentityType& face, const GlobalIndexType point ) { const LocalIndexType pointsCount = face.template getSubentitiesCount< 0 >(); for( LocalIndexType i = 0; i < pointsCount; i++ ) { diff --git a/src/TNL/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h index 6c51c8884..191f77fe5 100644 --- a/src/TNL/Meshes/Geometry/getDecomposedMesh.h +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -7,9 +7,9 @@ #include #include #include -#include -#include #include +#include +#include namespace TNL { namespace Meshes { @@ -21,67 +21,95 @@ struct TriangleConfig: public ParentConfig using CellTopology = Topologies::Triangle; }; -template< EntityDecomposerVersion EntityDecomposerVersion, +template< EntityDecomposerVersion DecomposerVersion, typename MeshConfig, std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polygon >::value, bool > = true > -auto -getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) +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 PointType = typename TriangleMesh::PointType; using GlobalIndexType = typename TriangleMesh::GlobalIndexType; using LocalIndexType = typename TriangleMesh::LocalIndexType; - using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion >; + using PointType = typename TriangleMesh::PointType; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, DecomposerVersion >; - TriangleMesh outMesh; MeshBuilder meshBuilder; - + const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); - const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 2 >(); - - // Find the number of points and cells in the outMesh - GlobalIndexType outPointsCount = inPointsCount; - GlobalIndexType outCellsCount = 0; - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 2 >( i ); - GlobalIndexType extraPointsCount, entitiesCount; - std::tie( extraPointsCount, entitiesCount ) = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); - outPointsCount += extraPointsCount; - outCellsCount += entitiesCount; - } + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< TriangleMesh::getMeshDimension() >(); + + // Find the number of output points and cells as well as + // starting indeces at which every cell will start writing new decomposed points and cells + using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; + Array< IndexPair, Devices::Host > indeces( inCellsCount ); + auto setCounts = [&] ( GlobalIndexType i ) { + const auto cell = inMesh.template getEntity< TriangleMesh::getMeshDimension() >( i ); + indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + }; + ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCounts ); + const auto lastCounts = indeces[ indeces.getSize() - 1 ]; + auto reduction = [] ( const IndexPair& a, const IndexPair& b ) -> IndexPair { + return { a.first + b.first, a.second + b.second }; + }; + inplaceExclusiveScan( indeces, 0, indeces.getSize(), reduction, std::make_pair( 0, 0 ) ); + const auto lastIndexPair = indeces[ indeces.getSize() - 1 ]; + const GlobalIndexType outPointsCount = inPointsCount + lastIndexPair.first + lastCounts.first; + const GlobalIndexType outCellsCount = lastIndexPair.second + lastCounts.second; meshBuilder.setPointsCount( outPointsCount ); meshBuilder.setCellsCount( outCellsCount ); // Copy the points from inMesh to outMesh - GlobalIndexType setPointsCount = 0; - for( ; setPointsCount < inPointsCount; setPointsCount++ ) { - meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); - } - - // Lambda for creating new points - auto createPointFunc = [&] ( const PointType & point ) { - const auto pointIdx = setPointsCount++; - meshBuilder.setPoint( pointIdx, point ); - return pointIdx; + auto copyPoint = [&] ( GlobalIndexType i ) mutable { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); }; + ParallelFor< Devices::Host >::exec( 0, inPointsCount, copyPoint ); - // Lambda for setting decomposed triangle in meshBuilder - GlobalIndexType setCellsCount = 0; - auto setDecomposedCellFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { - auto entitySeed = meshBuilder.getCellSeed( setCellsCount++ ); - entitySeed.setCornerId( 0, v0 ); - entitySeed.setCornerId( 1, v1 ); - entitySeed.setCornerId( 2, v2 ); + // Decompose each cell + auto decomposeCell = [&] ( GlobalIndexType i ) mutable { + const auto cell = inMesh.template getEntity< TriangleMesh::getMeshDimension() >( i ); + const auto indexPair = indeces[ 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( 0, inCellsCount, decomposeCell ); - // Decompose each cell - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 2 >( i ); - EntityDecomposer::decompose( cell, createPointFunc, setDecomposedCellFunc ); - } + return meshBuilder; +} + +template< EntityDecomposerVersion DecomposerVersion, + 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; } @@ -93,68 +121,99 @@ struct TetrahedronConfig: public ParentConfig using CellTopology = Topologies::Tetrahedron; }; -template< EntityDecomposerVersion EntityDecomposerVersion_, - EntityDecomposerVersion SubentityDecomposerVersion, +template< EntityDecomposerVersion DecomposerVersion, + EntityDecomposerVersion SubdecomposerVersion, typename MeshConfig, std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > -auto -getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) +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 LocalIndexType = typename TetrahedronMesh::LocalIndexType; using PointType = typename TetrahedronMesh::PointType; - using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVersion_, SubentityDecomposerVersion >; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polyhedron, DecomposerVersion, SubdecomposerVersion >; - TetrahedronMesh outMesh; - MeshBuilder< TetrahedronMesh > meshBuilder; + MeshBuilder meshBuilder; const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); - const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); - - // Find the number of points and cells in the outMesh - GlobalIndexType outPointsCount = inPointsCount; - GlobalIndexType outCellsCount = 0; - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - GlobalIndexType extraPointsCount, entitiesCount; - std::tie( extraPointsCount, entitiesCount ) = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); - outPointsCount += extraPointsCount; - outCellsCount += entitiesCount; - } + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< TetrahedronMesh::getMeshDimension() >(); + + using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; + Array< IndexPair, Devices::Host > indeces( inCellsCount ); + + // Find the number of output points and cells as well as + // starting indeces at which every cell will start writing new decomposed points and cells + auto setCounts = [&] ( GlobalIndexType i ) { + const auto cell = inMesh.template getEntity< TetrahedronMesh::getMeshDimension() >( i ); + indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + }; + ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCounts ); + const auto lastCounts = indeces[ indeces.getSize() - 1 ]; + auto reduction = [] ( const IndexPair& a, const IndexPair& b ) -> IndexPair { + return { a.first + b.first, a.second + b.second }; + }; + inplaceExclusiveScan( indeces, 0, indeces.getSize(), reduction, std::make_pair( 0, 0 ) ); + const auto lastIndexPair = indeces[ indeces.getSize() - 1 ]; + const GlobalIndexType outPointsCount = inPointsCount + lastIndexPair.first + lastCounts.first; + const GlobalIndexType outCellsCount = lastIndexPair.second + lastCounts.second; meshBuilder.setPointsCount( outPointsCount ); meshBuilder.setCellsCount( outCellsCount ); // Copy the points from inMesh to outMesh - GlobalIndexType setPointsCount = 0; - for( ; setPointsCount < inPointsCount; setPointsCount++ ) { - meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); - } - - // Lambda for creating new points - auto createPointFunc = [&] ( const PointType & point ) { - const auto pointIdx = setPointsCount++; - meshBuilder.setPoint( pointIdx, point ); - return pointIdx; + auto copyPoint = [&] ( GlobalIndexType i ) mutable { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); }; + ParallelFor< Devices::Host >::exec( 0, inPointsCount, copyPoint ); - // Lambda for setting decomposed cells in meshBuilder - GlobalIndexType setCellsCount = 0; - auto setDecomposedCellFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2, GlobalIndexType v3 ) { - auto entitySeed = meshBuilder.getCellSeed( setCellsCount++ ); - entitySeed.setCornerId( 0, v0 ); - entitySeed.setCornerId( 1, v1 ); - entitySeed.setCornerId( 2, v2 ); - entitySeed.setCornerId( 3, v3 ); + // Decompose each cell + auto decomposeCell = [&] ( GlobalIndexType i ) mutable { + const auto cell = inMesh.template getEntity< TetrahedronMesh::getMeshDimension() >( i ); + const auto indexPair = indeces[ 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( 0, inCellsCount, decomposeCell ); - // Decompose each cell - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - EntityDecomposer::decompose( cell, createPointFunc, setDecomposedCellFunc ); - } + 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; } -- GitLab From 34f8d97528a1b1516b49939b03ae75734cd1dbb6 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Tue, 7 Sep 2021 23:15:47 +0200 Subject: [PATCH 28/42] Refactored getPlanarMesh function to use ParallelFor --- src/Benchmarks/Mesh/MeshBenchmarks.h | 2 +- src/TNL/Meshes/Geometry/getDecomposedMesh.h | 43 +-- src/TNL/Meshes/Geometry/getPlanarMesh.h | 354 ++++++++++-------- .../initializer/EntitySeedMatrix.h | 38 ++ 4 files changed, 256 insertions(+), 181 deletions(-) diff --git a/src/Benchmarks/Mesh/MeshBenchmarks.h b/src/Benchmarks/Mesh/MeshBenchmarks.h index a1daac4a6..96159eb44 100644 --- a/src/Benchmarks/Mesh/MeshBenchmarks.h +++ b/src/Benchmarks/Mesh/MeshBenchmarks.h @@ -369,7 +369,7 @@ struct MeshBenchmarks static void benchmark_planar( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { auto benchmark_func = [&] () { - const auto planarMesh = getPlanarMesh< DecomposerVersion >( mesh_src ); + auto meshBuilder = planarCorrection< DecomposerVersion >( mesh_src ); }; benchmark.time< Devices::Host >( "CPU", diff --git a/src/TNL/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h index 191f77fe5..3b42bf20c 100644 --- a/src/TNL/Meshes/Geometry/getDecomposedMesh.h +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -38,29 +38,30 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) using LocalIndexType = typename TriangleMesh::LocalIndexType; 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< TriangleMesh::getMeshDimension() >(); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< CellDimension >(); // Find the number of output points and cells as well as // starting indeces at which every cell will start writing new decomposed points and cells using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; - Array< IndexPair, Devices::Host > indeces( inCellsCount ); + Array< IndexPair, Devices::Host > indeces( inCellsCount + 1 ); auto setCounts = [&] ( GlobalIndexType i ) { - const auto cell = inMesh.template getEntity< TriangleMesh::getMeshDimension() >( i ); + const auto cell = inMesh.template getEntity< CellDimension >( i ); indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); }; ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCounts ); - const auto lastCounts = indeces[ indeces.getSize() - 1 ]; + indeces[ 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( indeces, 0, indeces.getSize(), reduction, std::make_pair( 0, 0 ) ); - const auto lastIndexPair = indeces[ indeces.getSize() - 1 ]; - const GlobalIndexType outPointsCount = inPointsCount + lastIndexPair.first + lastCounts.first; - const GlobalIndexType outCellsCount = lastIndexPair.second + lastCounts.second; + const auto& reduceResult = indeces[ inCellsCount ]; + const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; + const GlobalIndexType outCellsCount = reduceResult.second; meshBuilder.setPointsCount( outPointsCount ); meshBuilder.setCellsCount( outCellsCount ); @@ -72,8 +73,8 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) // Decompose each cell auto decomposeCell = [&] ( GlobalIndexType i ) mutable { - const auto cell = inMesh.template getEntity< TriangleMesh::getMeshDimension() >( i ); - const auto indexPair = indeces[ i ]; + const auto cell = inMesh.template getEntity< CellDimension >( i ); + const auto& indexPair = indeces[ i ]; // Lambda for adding new points GlobalIndexType setPointIndex = inPointsCount + indexPair.first; @@ -126,7 +127,7 @@ template< EntityDecomposerVersion DecomposerVersion, 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 ) +decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) { using namespace TNL; using namespace TNL::Containers; @@ -139,30 +140,30 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) using LocalIndexType = typename TetrahedronMesh::LocalIndexType; 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< TetrahedronMesh::getMeshDimension() >(); - - using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; - Array< IndexPair, Devices::Host > indeces( inCellsCount ); + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< CellDimension >(); // Find the number of output points and cells as well as // starting indeces at which every cell will start writing new decomposed points and cells + using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; + Array< IndexPair, Devices::Host > indeces( inCellsCount + 1 ); auto setCounts = [&] ( GlobalIndexType i ) { - const auto cell = inMesh.template getEntity< TetrahedronMesh::getMeshDimension() >( i ); + const auto cell = inMesh.template getEntity< CellDimension >( i ); indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); }; ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCounts ); - const auto lastCounts = indeces[ indeces.getSize() - 1 ]; + indeces[ 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( indeces, 0, indeces.getSize(), reduction, std::make_pair( 0, 0 ) ); - const auto lastIndexPair = indeces[ indeces.getSize() - 1 ]; - const GlobalIndexType outPointsCount = inPointsCount + lastIndexPair.first + lastCounts.first; - const GlobalIndexType outCellsCount = lastIndexPair.second + lastCounts.second; + const auto& reduceResult = indeces[ inCellsCount ]; + const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; + const GlobalIndexType outCellsCount = reduceResult.second; meshBuilder.setPointsCount( outPointsCount ); meshBuilder.setCellsCount( outCellsCount ); @@ -174,8 +175,8 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) // Decompose each cell auto decomposeCell = [&] ( GlobalIndexType i ) mutable { - const auto cell = inMesh.template getEntity< TetrahedronMesh::getMeshDimension() >( i ); - const auto indexPair = indeces[ i ]; + const auto cell = inMesh.template getEntity< CellDimension >( i ); + const auto& indexPair = indeces[ i ]; // Lambda for adding new points GlobalIndexType setPointIndex = inPointsCount + indexPair.first; diff --git a/src/TNL/Meshes/Geometry/getPlanarMesh.h b/src/TNL/Meshes/Geometry/getPlanarMesh.h index 919eae67d..1197d8400 100644 --- a/src/TNL/Meshes/Geometry/getPlanarMesh.h +++ b/src/TNL/Meshes/Geometry/getPlanarMesh.h @@ -9,18 +9,24 @@ #include #include #include +#include +#include namespace TNL { namespace Meshes { // 3D Polygon Mesh -template< EntityDecomposerVersion EntityDecomposerVersion_, +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 > -Mesh< MeshConfig, Devices::Host > -getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) +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 GlobalIndexType = typename PolygonMesh::GlobalIndexType; @@ -28,242 +34,272 @@ getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) using PointType = typename PolygonMesh::PointType; using RealType = typename PolygonMesh::RealType; using BoolVector = Containers::Vector< bool, Devices::Host, GlobalIndexType >; - using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion_ >; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, DecomposerVersion >; + constexpr int CellDimension = PolygonMesh::getMeshDimension(); constexpr RealType precision{ 1e-6 }; - PolygonMesh outMesh; MeshBuilder meshBuilder; const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); - const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 2 >(); - - BoolVector planarCache; - planarCache.setSize( inCellsCount ); - - // Count the number of points and cells in the outMesh - GlobalIndexType outPointsCount = inPointsCount; - GlobalIndexType outCellsCount = 0; - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 2 >( i ); - const bool planar = isPlanar( inMesh, cell, precision ); - planarCache.setElement( i, planar ); - if( planar ) { // Cell is not decomposed - outCellsCount++; + const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< CellDimension >(); + + // Find the number of output points and cells as well as + // starting indeces at which every cell will start writing new points and cells + using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; + Array< IndexPair, Devices::Host > indeces( inCellsCount + 1 ); + auto setCounts = [&] ( GlobalIndexType i ) { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + if( isPlanar( inMesh, cell, precision ) ) { + indeces[ i ] = { 0, 1 }; // cell is not decomposed (0 extra points, 1 cell) } - else { // Cell is decomposed - GlobalIndexType extraPointsCount, entitiesCount; - std::tie( extraPointsCount, entitiesCount ) = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); - outPointsCount += extraPointsCount; - outCellsCount += entitiesCount; + else { + indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); } - } + }; + ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCounts ); + indeces[ 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( indeces, 0, indeces.getSize(), reduction, std::make_pair( 0, 0 ) ); + const auto& reduceResult = indeces[ inCellsCount ]; + const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; + const GlobalIndexType outCellsCount = reduceResult.second; meshBuilder.setPointsCount( outPointsCount ); meshBuilder.setCellsCount( outCellsCount ); - // copy the points from inMesh to outMesh - GlobalIndexType setPointsCount = 0; - for( ; setPointsCount < inPointsCount; setPointsCount++ ) { - meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); - } - - // Lambda for creating new points - auto createPointFunc = [&] ( const PointType& point ) { - const auto pointIdx = setPointsCount++; - meshBuilder.setPoint( pointIdx, point ); - return pointIdx; + // Copy the points from inMesh to outMesh + auto copyPoint = [&] ( GlobalIndexType i ) mutable { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); }; + ParallelFor< Devices::Host >::exec( 0, inPointsCount, copyPoint ); // set corner counts for cells - for( GlobalIndexType i = 0, o = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 2 >( i ); - const bool planar = planarCache[ i ]; - if( planar ) { // Copy planar cells + auto setCornersCount = [&] ( GlobalIndexType i ) mutable { + GlobalIndexType cellIndex = indeces[ i ].second; + const GlobalIndexType nextCellIndex = indeces[ 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 >(); - meshBuilder.setCellCornersCount( o++, verticesCount ); + meshBuilder.setCellCornersCount( cellIndex, verticesCount ); } - else { // Decompose non-planar cells - GlobalIndexType entitiesCount; - std::tie( std::ignore, entitiesCount ) = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); - for( GlobalIndexType j = 0; j < entitiesCount; j++ ) { - meshBuilder.setCellCornersCount( o++, 3 ); + else { // cell is not planar (cell is decomposed) + for( ; cellIndex < nextCellIndex; cellIndex++ ) { + meshBuilder.setCellCornersCount( cellIndex, 3 ); } } - } - meshBuilder.initializeCellSeeds(); - - // Lambda for setting corner ids of decomposed cells - GlobalIndexType setCellsCount = 0; - auto setDecomposedCellFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { - auto seed = meshBuilder.getCellSeed( setCellsCount++ ); - seed.setCornerId( 0, v0 ); - seed.setCornerId( 1, v1 ); - seed.setCornerId( 2, v2 ); }; + ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCornersCount ); + meshBuilder.initializeCellSeeds(); // Decompose non-planar cells and copy the rest - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 2 >( i ); - const bool planar = planarCache[ i ]; - if( planar ) { // Copy planar cells - auto seed = meshBuilder.getCellSeed( setCellsCount++ ); + auto decomposeCell = [&] ( GlobalIndexType i ) mutable { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + const auto& indexPair = indeces[ i ]; + const auto& nextIndexPair = indeces[ 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 { // Decompose non-planar cells - EntityDecomposer::decompose( cell, createPointFunc, setDecomposedCellFunc ); + 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( 0, inCellsCount, decomposeCell ); - meshBuilder.build( outMesh ); - return outMesh; + return meshBuilder; } // Polyhedral Mesh -template< EntityDecomposerVersion EntityDecomposerVersion_, +template< EntityDecomposerVersion DecomposerVersion, typename MeshConfig, std::enable_if_t< std::is_same< typename MeshConfig::CellTopology, Topologies::Polyhedron >::value, bool > = true > -Mesh< MeshConfig, Devices::Host > -getPlanarMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) +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 GlobalIndexType = typename PolyhedronMesh::GlobalIndexType; using LocalIndexType = typename PolyhedronMesh::LocalIndexType; using PointType = typename PolyhedronMesh::PointType; using RealType = typename PolyhedronMesh::RealType; using FaceMapArray = Containers::Array< std::pair< GlobalIndexType, GlobalIndexType >, Devices::Host, GlobalIndexType >; - using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersion_ >; + using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, DecomposerVersion >; + constexpr int CellDimension = PolyhedronMesh::getMeshDimension(); + constexpr int FaceDimension = CellDimension - 1; constexpr RealType precision{ 1e-6 }; - PolyhedronMesh outMesh; MeshBuilder< PolyhedronMesh > meshBuilder; const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); - const GlobalIndexType inFacesCount = inMesh.template getEntitiesCount< 2 >(); - const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< 3 >(); - - FaceMapArray faceMap( inFacesCount ); // Mapping of original face indeces to a group of decomposed face indices - - // Count the number of points and faces in the outMesh and setup faceMap - GlobalIndexType outPointsCount = inPointsCount; - GlobalIndexType outFacesCount = 0; - for( GlobalIndexType i = 0; i < inFacesCount; i++ ) { - const auto face = inMesh.template getEntity< 2 >( i ); + 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 indeces at which every face will start writing new points and faces + using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; + Array< IndexPair, Devices::Host > indeces( inFacesCount + 1 ); + auto setCounts = [&] ( GlobalIndexType i ) { + const auto face = inMesh.template getEntity< FaceDimension >( i ); if( isPlanar( inMesh, face, precision ) ) { - const auto startFaceIdx = outFacesCount; - const auto endFaceIdx = ++outFacesCount; // Planar faces aren't decomposed - faceMap[ i ] = { startFaceIdx, endFaceIdx }; + indeces[ i ] = { 0, 1 }; // face is not decomposed (0 extra points, 1 face) } else { - GlobalIndexType extraPointsCount, entitiesCount; - std::tie( extraPointsCount, entitiesCount ) = EntityDecomposer::getExtraPointsAndEntitiesCount( face ); - outPointsCount += extraPointsCount; - const auto startFaceIdx = outFacesCount; - outFacesCount += entitiesCount; - const auto endFaceIdx = outFacesCount; - faceMap[ i ] = { startFaceIdx, endFaceIdx }; + indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( face ); } - } - + }; + ParallelFor< Devices::Host >::exec( 0, inFacesCount, setCounts ); + indeces[ 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( indeces, 0, indeces.getSize(), reduction, std::make_pair( 0, 0 ) ); + const auto& reduceResult = indeces[ inFacesCount ]; + const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; + const GlobalIndexType outFacesCount = reduceResult.second; meshBuilder.setPointsCount( outPointsCount ); meshBuilder.setFacesCount( outFacesCount ); meshBuilder.setCellsCount( inCellsCount ); // The number of cells stays the same // Copy the points from inMesh to outMesh - GlobalIndexType setPointsCount = 0; - for( ; setPointsCount < inPointsCount; setPointsCount++ ) { - meshBuilder.setPoint( setPointsCount, inMesh.getPoint( setPointsCount ) ); - } + auto copyPoint = [&] ( GlobalIndexType i ) mutable { + meshBuilder.setPoint( i, inMesh.getPoint( i ) ); + }; + ParallelFor< Devices::Host >::exec( 0, inPointsCount, copyPoint ); - // set cell corner counts - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - const LocalIndexType cellFacesCount = cell.template getSubentitiesCount< 2 >(); + // set corner counts for cells + auto setCellCornersCount = [&] ( GlobalIndexType i ) mutable { + const auto cell = inMesh.template getEntity< CellDimension >( i ); + const LocalIndexType cellFacesCount = cell.template getSubentitiesCount< FaceDimension >(); - // Count the number of faces in the cell + // 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< 2 >( j ); - const auto & faceMapping = faceMap[ faceIdx ]; - cornersCount += faceMapping.second - faceMapping.first; + const GlobalIndexType faceIdx = cell.template getSubentityIndex< FaceDimension >( j ); + cornersCount += indeces[ faceIdx + 1 ].second - indeces[ faceIdx ].second; } meshBuilder.setCellCornersCount( i, cornersCount ); - } - + }; + ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCellCornersCount ); meshBuilder.initializeCellSeeds(); - // Set cell corner ids - for( GlobalIndexType i = 0; i < inCellsCount; i++ ) { - const auto cell = inMesh.template getEntity< 3 >( i ); - const LocalIndexType cellFacesCount = cell.template getSubentitiesCount< 2 >(); - + // 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< 2 >( j ); - const auto & faceMapping = faceMap[ faceIdx ]; - auto cellSeed = meshBuilder.getCellSeed( i ); - for( GlobalIndexType k = faceMapping.first; k < faceMapping.second; k++ ) { + const GlobalIndexType faceIdx = cell.template getSubentityIndex< FaceDimension >( j ); + const GlobalIndexType endFaceIdx = indeces[ faceIdx + 1 ].second; + for( GlobalIndexType k = indeces[ faceIdx ].second; k < endFaceIdx; k++ ) { cellSeed.setCornerId( o++, k ); } } - } - - // set face corners count - GlobalIndexType setFacesCount = 0; - for( GlobalIndexType i = 0; i < inFacesCount; i++ ) { - const auto & faceMapping = faceMap[ i ]; - const bool isPlanarRes = ( faceMapping.second - faceMapping.first ) == 1; - if( isPlanarRes ) { - const auto face = inMesh.template getEntity< 2 >( i ); + }; + ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCellCornersIds ); + + // set corner counts for faces + auto setFaceCornersCount = [&] ( GlobalIndexType i ) mutable { + GlobalIndexType faceIndex = indeces[ i ].second; + const GlobalIndexType nextFaceIndex = indeces[ 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 >(); - meshBuilder.setFaceCornersCount( setFacesCount++, verticesCount ); + meshBuilder.setFaceCornersCount( faceIndex, verticesCount ); } - else { - for( GlobalIndexType j = faceMapping.first; j < faceMapping.second; j++ ) { - meshBuilder.setFaceCornersCount( setFacesCount++, 3 ); + else { // face is not planar (it is decomposed) + for( ; faceIndex < nextFaceIndex; faceIndex++ ) { + meshBuilder.setFaceCornersCount( faceIndex, 3 ); } } - } - meshBuilder.initializeFaceSeeds(); - - // Lambda for creating new points - auto createPointFunc = [&] ( const PointType& point ) { - const auto pointIdx = setPointsCount++; - meshBuilder.setPoint( pointIdx, point ); - return pointIdx; - }; - - // Lambda for setting corner ids of decomposed faces - setFacesCount = 0; - auto setDecomposedFaceFunc = [&] ( GlobalIndexType v0, GlobalIndexType v1, GlobalIndexType v2 ) { - const GlobalIndexType faceId = setFacesCount++; - auto seed = meshBuilder.getFaceSeed( faceId ); - seed.setCornerId( 0, v0 ); - seed.setCornerId( 1, v1 ); - seed.setCornerId( 2, v2 ); }; + ParallelFor< Devices::Host >::exec( 0, inFacesCount, setFaceCornersCount ); + meshBuilder.initializeFaceSeeds(); // Decompose non-planar faces and copy the rest - for( GlobalIndexType i = 0; i < inFacesCount; i++ ) { - const auto face = inMesh.template getEntity< 2 >( i ); - const auto verticesCount = face.template getSubentitiesCount< 0 >(); - const auto & faceMapping = faceMap[ i ]; - const bool isPlanarRes = ( faceMapping.second - faceMapping.first ) == 1; // Face was planar if face maps only onto 1 face - if( isPlanarRes ) { // Copy planar faces - const GlobalIndexType faceId = setFacesCount++; + auto decomposeFace = [&] ( GlobalIndexType i ) mutable { + const auto face = inMesh.template getEntity< FaceDimension >( i ); + const auto& indexPair = indeces[ i ]; + const auto& nextIndexPair = indeces[ 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++ ) { - meshBuilder.getFaceSeed( faceId ).setCornerId( j, face.template getSubentityIndex< 0 >( j ) ); + seed.setCornerId( j, face.template getSubentityIndex< 0 >( j ) ); } } - else { // Decompose non-planar cells - EntityDecomposer::decompose( face, createPointFunc, setDecomposedFaceFunc ); + 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( 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 >; - faceMap.reset(); + Mesh outMesh; + auto meshBuilder = planarCorrection< DecomposerVersion >( inMesh ); meshBuilder.build( outMesh ); return outMesh; } diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h index 0d9460ea9..0d16cf79f 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h @@ -28,6 +28,18 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, false > using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + EntitySeedMatrix() = default; + + EntitySeedMatrix( const EntitySeedMatrix& other ) + { + this->matrix = other.matrix; + } + + EntitySeedMatrix( EntitySeedMatrix&& other ) + { + this->matrix = std::move( other.matrix ); + } + class EntitySeedMatrixSeed { using RowView = typename SubentityMatrixType::RowView; @@ -156,6 +168,18 @@ class EntitySeedMatrix< MeshConfig, Topologies::Vertex, false > using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< 0 >; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + EntitySeedMatrix() = default; + + EntitySeedMatrix( const EntitySeedMatrix& other ) + { + this->matrix = other.matrix; + } + + EntitySeedMatrix( EntitySeedMatrix&& other ) + { + this->matrix = std::move( other.matrix ); + } + class EntitySeedMatrixSeed { using RowView = typename SubentityMatrixType::RowView; @@ -285,6 +309,20 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, true > using SubentityMatrixType = typename MeshTraitsType::template SubentityMatrixType< EntityTopology::dimension >; using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; + EntitySeedMatrix() = default; + + EntitySeedMatrix( const EntitySeedMatrix& other ) + { + this->matrix = other.matrix; + this->counts = other.counts; + } + + EntitySeedMatrix( EntitySeedMatrix&& other ) + { + this->matrix = std::move( other.matrix ); + this->counts = std::move( other.counts ); + } + class EntitySeedMatrixSeed { using RowView = typename SubentityMatrixType::RowView; -- GitLab From 773f850e41fcd04501d2ee58d0684fc329a4ebac Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Sat, 11 Sep 2021 22:50:56 +0200 Subject: [PATCH 29/42] Refactored the way how entity counts and corners counts are passed into MeshBuilder --- src/TNL/Meshes/Geometry/getDecomposedMesh.h | 6 +- src/TNL/Meshes/Geometry/getPlanarMesh.h | 33 ++--- src/TNL/Meshes/MeshBuilder.h | 43 +++--- .../initializer/EntitySeedMatrix.h | 30 +++-- src/TNL/Meshes/Readers/MeshReader.h | 21 +-- src/Tools/tnl-grid-to-mesh.cpp | 9 +- .../DistributedMeshes/DistributedMeshTest.h | 3 +- src/UnitTests/Meshes/EntityTagsTest.h | 3 +- src/UnitTests/Meshes/MeshGeometryTest.h | 127 +++++------------- src/UnitTests/Meshes/MeshOrderingTest.h | 5 +- src/UnitTests/Meshes/MeshTest.h | 80 ++++------- src/UnitTests/Meshes/MeshTraverserTest.h | 6 +- 12 files changed, 136 insertions(+), 230 deletions(-) diff --git a/src/TNL/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h index 3b42bf20c..af17a9d88 100644 --- a/src/TNL/Meshes/Geometry/getDecomposedMesh.h +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -62,8 +62,7 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) const auto& reduceResult = indeces[ inCellsCount ]; const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; const GlobalIndexType outCellsCount = reduceResult.second; - meshBuilder.setPointsCount( outPointsCount ); - meshBuilder.setCellsCount( outCellsCount ); + meshBuilder.setEntitiesCount( outPointsCount, outCellsCount ); // Copy the points from inMesh to outMesh auto copyPoint = [&] ( GlobalIndexType i ) mutable { @@ -164,8 +163,7 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) const auto& reduceResult = indeces[ inCellsCount ]; const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; const GlobalIndexType outCellsCount = reduceResult.second; - meshBuilder.setPointsCount( outPointsCount ); - meshBuilder.setCellsCount( outCellsCount ); + meshBuilder.setEntitiesCount( outPointsCount, outCellsCount ); // Copy the points from inMesh to outMesh auto copyPoint = [&] ( GlobalIndexType i ) mutable { diff --git a/src/TNL/Meshes/Geometry/getPlanarMesh.h b/src/TNL/Meshes/Geometry/getPlanarMesh.h index 1197d8400..aca91c073 100644 --- a/src/TNL/Meshes/Geometry/getPlanarMesh.h +++ b/src/TNL/Meshes/Geometry/getPlanarMesh.h @@ -29,6 +29,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) 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; @@ -66,8 +67,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) const auto& reduceResult = indeces[ inCellsCount ]; const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; const GlobalIndexType outCellsCount = reduceResult.second; - meshBuilder.setPointsCount( outPointsCount ); - meshBuilder.setCellsCount( outCellsCount ); + meshBuilder.setEntitiesCount( outPointsCount, outCellsCount ); // Copy the points from inMesh to outMesh auto copyPoint = [&] ( GlobalIndexType i ) mutable { @@ -76,6 +76,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) ParallelFor< Devices::Host >::exec( 0, inPointsCount, copyPoint ); // set corner counts for cells + NeighborCountsArray cellCornersCounts( outCellsCount ); auto setCornersCount = [&] ( GlobalIndexType i ) mutable { GlobalIndexType cellIndex = indeces[ i ].second; const GlobalIndexType nextCellIndex = indeces[ i + 1 ].second; @@ -84,16 +85,16 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) 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 >(); - meshBuilder.setCellCornersCount( cellIndex, verticesCount ); + cellCornersCounts[ cellIndex ] = verticesCount; } else { // cell is not planar (cell is decomposed) for( ; cellIndex < nextCellIndex; cellIndex++ ) { - meshBuilder.setCellCornersCount( cellIndex, 3 ); + cellCornersCounts[ cellIndex ] = 3; } } }; ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCornersCount ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( std::move( cellCornersCounts ) ); // Decompose non-planar cells and copy the rest auto decomposeCell = [&] ( GlobalIndexType i ) mutable { @@ -147,18 +148,19 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) 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 FaceMapArray = Containers::Array< std::pair< GlobalIndexType, GlobalIndexType >, Devices::Host, GlobalIndexType >; using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, DecomposerVersion >; constexpr int CellDimension = PolyhedronMesh::getMeshDimension(); constexpr int FaceDimension = CellDimension - 1; constexpr RealType precision{ 1e-6 }; - MeshBuilder< PolyhedronMesh > meshBuilder; + MeshBuilder meshBuilder; const GlobalIndexType inPointsCount = inMesh.template getEntitiesCount< 0 >(); const GlobalIndexType inFacesCount = inMesh.template getEntitiesCount< FaceDimension >(); @@ -186,9 +188,8 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) const auto& reduceResult = indeces[ inFacesCount ]; const GlobalIndexType outPointsCount = inPointsCount + reduceResult.first; const GlobalIndexType outFacesCount = reduceResult.second; - meshBuilder.setPointsCount( outPointsCount ); - meshBuilder.setFacesCount( outFacesCount ); - meshBuilder.setCellsCount( inCellsCount ); // The number of cells stays the same + 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 { @@ -197,6 +198,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) ParallelFor< Devices::Host >::exec( 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 >(); @@ -208,10 +210,10 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) cornersCount += indeces[ faceIdx + 1 ].second - indeces[ faceIdx ].second; } - meshBuilder.setCellCornersCount( i, cornersCount ); + cellCornersCounts[ i ] = cornersCount; }; ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCellCornersCount ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( std::move( cellCornersCounts ) ); // Set corner ids for cells auto setCellCornersIds = [&] ( GlobalIndexType i ) mutable { @@ -229,6 +231,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCellCornersIds ); // set corner counts for faces + NeighborCountsArray faceCornersCounts( outFacesCount ); auto setFaceCornersCount = [&] ( GlobalIndexType i ) mutable { GlobalIndexType faceIndex = indeces[ i ].second; const GlobalIndexType nextFaceIndex = indeces[ i + 1 ].second; @@ -236,16 +239,16 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) 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 >(); - meshBuilder.setFaceCornersCount( faceIndex, verticesCount ); + faceCornersCounts[ faceIndex ] = verticesCount; } else { // face is not planar (it is decomposed) for( ; faceIndex < nextFaceIndex; faceIndex++ ) { - meshBuilder.setFaceCornersCount( faceIndex, 3 ); + faceCornersCounts[ faceIndex ] = 3; } } }; ParallelFor< Devices::Host >::exec( 0, inFacesCount, setFaceCornersCount ); - meshBuilder.initializeFaceSeeds(); + meshBuilder.setFaceCornersCounts( std::move( faceCornersCounts ) ); // Decompose non-planar faces and copy the rest auto decomposeFace = [&] ( GlobalIndexType i ) mutable { diff --git a/src/TNL/Meshes/MeshBuilder.h b/src/TNL/Meshes/MeshBuilder.h index 303113a17..aa10a8a24 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 { @@ -35,45 +36,45 @@ public: using CellSeedType = typename CellSeedMatrixType::EntitySeedMatrixSeed; using FaceSeedMatrixType = typename MeshTraitsType::FaceSeedMatrixType; using FaceSeedType = typename FaceSeedMatrixType::EntitySeedMatrixSeed; + using NeighborCountsArray = typename MeshTraitsType::NeighborCountsArray; - void setPointsCount( const GlobalIndexType& points ) + void setEntitiesCount( const GlobalIndexType& points, + const GlobalIndexType& cells = 0, + const GlobalIndexType& faces = 0 ) { this->points.setSize( points ); this->pointsSet.setSize( points ); pointsSet.setValue( false ); - } - void setFacesCount( const GlobalIndexType& facesCount ) - { - this->faceSeeds.setDimensions( facesCount, this->points.getSize() ); - } - - void setFaceCornersCount( const GlobalIndexType& faceIndex, const LocalIndexType& cornersCount ) - { - this->faceSeeds.setEntityCornersCount( faceIndex, cornersCount ); + 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 initializeFaceSeeds() + void setFaceCornersCounts( const NeighborCountsArray& counts ) { - this->faceSeeds.initializeRows(); + this->faceSeeds.setEntityCornersCounts( counts ); } - void setCellsCount( const GlobalIndexType& cellsCount ) + void setFaceCornersCounts( NeighborCountsArray&& counts ) { - if( getFacesCount() == 0 ) // faceSeeds aren't used ( cellSeeds store indeces of points ) - this->cellSeeds.setDimensions( cellsCount, getPointsCount() ); - else // faceSeeds are used ( cellSeeds store indeces of faces ) - this->cellSeeds.setDimensions( cellsCount, getFacesCount() ); + this->faceSeeds.setEntityCornersCounts( std::move( counts ) ); } - void setCellCornersCount( const GlobalIndexType& cellIndex, const LocalIndexType& cornersCount ) + void setCellCornersCounts( const NeighborCountsArray& counts ) { - this->cellSeeds.setEntityCornersCount( cellIndex, cornersCount ); + this->cellSeeds.setEntityCornersCounts( counts ); } - void initializeCellSeeds() + void setCellCornersCounts( NeighborCountsArray&& counts ) { - this->cellSeeds.initializeRows(); + this->cellSeeds.setEntityCornersCounts( std::move( counts ) ); } GlobalIndexType getPointsCount() const diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h index 0d16cf79f..4dd2f9a3f 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h @@ -104,12 +104,14 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, false > } // This method is only here for compatibility with specialization for dynamic entity topologies - void setEntityCornersCount( const GlobalIndexType& entityIndex, const LocalIndexType& count ) - {} + void setEntityCornersCounts( const NeighborCountsArray& counts ) + { + } // This method is only here for compatibility with specialization for dynamic entity topologies - void initializeRows() - {} + void setEntityCornersCounts( NeighborCountsArray&& counts ) + { + } void reset() { @@ -244,12 +246,14 @@ class EntitySeedMatrix< MeshConfig, Topologies::Vertex, false > } // This method is only here for compatibility with specialization for dynamic entity topologies - void setEntityCornersCount( const GlobalIndexType& entityIndex, const LocalIndexType& count ) - {} + void setEntityCornersCounts( const NeighborCountsArray& counts ) + { + } // This method is only here for compatibility with specialization for dynamic entity topologies - void initializeRows() - {} + void setEntityCornersCounts( NeighborCountsArray&& counts ) + { + } void reset() { @@ -387,14 +391,16 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, true > matrix.setDimensions( entitiesCount, pointsCount ); } - void setEntityCornersCount( const GlobalIndexType& entityIndex, const LocalIndexType& count ) + void setEntityCornersCounts( const NeighborCountsArray& counts_ ) { - counts.setElement( entityIndex, count ); + this->counts = counts_; + matrix.setRowCapacities( this->counts ); } - void initializeRows() + void setEntityCornersCounts( NeighborCountsArray&& counts_ ) { - matrix.setRowCapacities( counts ); + this->counts = std::move( counts_ ); + matrix.setRowCapacities( this->counts ); } void reset() diff --git a/src/TNL/Meshes/Readers/MeshReader.h b/src/TNL/Meshes/Readers/MeshReader.h index c52f65d4c..e18e6577b 100644 --- a/src/TNL/Meshes/Readers/MeshReader.h +++ b/src/TNL/Meshes/Readers/MeshReader.h @@ -167,15 +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.setFacesCount( NumberOfFaces ); - meshBuilder.setCellsCount( NumberOfCells ); - + meshBuilder.setEntitiesCount( NumberOfPoints, NumberOfCells, NumberOfFaces ); + // assign points visit( [&meshBuilder](auto&& array) { PointType p; @@ -198,14 +197,17 @@ public: 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 ]; - meshBuilder.setFaceCornersCount( i, offsetEnd - offsetStart ); + cornersCounts[ i ] = offsetEnd - offsetStart; offsetStart = offsetEnd; } - meshBuilder.initializeFaceSeeds(); + meshBuilder.setFaceCornersCounts( std::move( cornersCounts ) ); + // Set corner ids offsetStart = 0; for( std::size_t i = 0; i < NumberOfFaces; i++ ) { FaceSeedType seed = meshBuilder.getFaceSeed( i ); @@ -224,14 +226,17 @@ public: using mpark::get; 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++ ) { const std::size_t offsetEnd = offsets[ i ]; - meshBuilder.setCellCornersCount( i, offsetEnd - offsetStart ); + cornersCounts[ i ] = offsetEnd - offsetStart; offsetStart = offsetEnd; } - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( std::move( cornersCounts ) ); + // Set corner ids offsetStart = 0; for( std::size_t i = 0; i < NumberOfCells; i++ ) { CellSeedType seed = meshBuilder.getCellSeed( i ); diff --git a/src/Tools/tnl-grid-to-mesh.cpp b/src/Tools/tnl-grid-to-mesh.cpp index e2d255eb0..193f60620 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/UnitTests/Meshes/DistributedMeshes/DistributedMeshTest.h b/src/UnitTests/Meshes/DistributedMeshes/DistributedMeshTest.h index 18ed6b4bf..570c59cbb 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 775cb1aeb..f53755caf 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/MeshGeometryTest.h b/src/UnitTests/Meshes/MeshGeometryTest.h index df02b42a5..475a9b14a 100644 --- a/src/UnitTests/Meshes/MeshGeometryTest.h +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -82,16 +82,15 @@ TEST( MeshGeometryTest, Polygon2DAreaTest ) PolygonTestMesh mesh; MeshBuilder< PolygonTestMesh > meshBuilder; - meshBuilder.setPointsCount( 5 ); + 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.setCellsCount( 1 ); - meshBuilder.setCellCornersCount( 0, 5 ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( { 5 } ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); @@ -131,17 +130,15 @@ TEST( MeshGeometryTest, Polygon3DAreaTest ) PolygonTestMesh mesh; MeshBuilder< PolygonTestMesh > meshBuilder; + meshBuilder.setEntitiesCount( 5, 1 ); - meshBuilder.setPointsCount( 5 ); meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); meshBuilder.setPoint( 3, point3 ); meshBuilder.setPoint( 4, point4 ); - meshBuilder.setCellsCount( 1 ); - meshBuilder.setCellCornersCount( 0, 5 ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( { 5 } ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); @@ -173,7 +170,8 @@ TEST( MeshGeometryTest, WedgeAreaTest ) WedgeTestMesh mesh; MeshBuilder< WedgeTestMesh > meshBuilder; - meshBuilder.setPointsCount( 6 ); + meshBuilder.setEntitiesCount( 6, 1 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); @@ -181,7 +179,6 @@ TEST( MeshGeometryTest, WedgeAreaTest ) meshBuilder.setPoint( 4, point4 ); meshBuilder.setPoint( 5, point5 ); - meshBuilder.setCellsCount( 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -214,14 +211,14 @@ TEST( MeshGeometryTest, PyramidAreaTest ) PyramidTestMesh mesh; MeshBuilder< PyramidTestMesh > meshBuilder; - meshBuilder.setPointsCount( 5 ); + 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.setCellsCount( 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -257,7 +254,8 @@ TEST( MeshGeometryTest, PolyhedronAreaTest ) PolyhedronTestMesh mesh; MeshBuilder< PolyhedronTestMesh > meshBuilder; - meshBuilder.setPointsCount( 9 ); + meshBuilder.setEntitiesCount( 9, 1, 9 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); @@ -268,17 +266,7 @@ TEST( MeshGeometryTest, PolyhedronAreaTest ) meshBuilder.setPoint( 7, point7 ); meshBuilder.setPoint( 8, point8 ); - meshBuilder.setFacesCount( 9 ); - meshBuilder.setFaceCornersCount( 0, 4 ); - meshBuilder.setFaceCornersCount( 1, 4 ); - meshBuilder.setFaceCornersCount( 2, 4 ); - meshBuilder.setFaceCornersCount( 3, 4 ); - meshBuilder.setFaceCornersCount( 4, 4 ); - meshBuilder.setFaceCornersCount( 5, 3 ); - meshBuilder.setFaceCornersCount( 6, 3 ); - meshBuilder.setFaceCornersCount( 7, 3 ); - meshBuilder.setFaceCornersCount( 8, 3 ); - meshBuilder.initializeFaceSeeds(); + meshBuilder.setFaceCornersCounts( { 4, 4, 4, 4, 4, 3, 3, 3, 3 } ); meshBuilder.getFaceSeed( 0 ).setCornerId( 0, 2 ); meshBuilder.getFaceSeed( 0 ).setCornerId( 1, 3 ); @@ -321,9 +309,7 @@ TEST( MeshGeometryTest, PolyhedronAreaTest ) meshBuilder.getFaceSeed( 8 ).setCornerId( 1, 4 ); meshBuilder.getFaceSeed( 8 ).setCornerId( 2, 8 ); - meshBuilder.setCellsCount( 1 ); - meshBuilder.setCellCornersCount( 0, 9 ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( { 9 } ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); @@ -378,7 +364,8 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) PolygonTestMesh mesh; MeshBuilder< PolygonTestMesh > meshBuilder; - meshBuilder.setPointsCount( 10 ); + meshBuilder.setEntitiesCount( 10, 6 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); @@ -390,14 +377,7 @@ TEST( MeshGeometryTest, Polygon3DIsPlanarTest ) meshBuilder.setPoint( 8, point3_ ); meshBuilder.setPoint( 9, point4_ ); - meshBuilder.setCellsCount( 6 ); - meshBuilder.setCellCornersCount( 0, 5 ); - meshBuilder.setCellCornersCount( 1, 5 ); - meshBuilder.setCellCornersCount( 2, 5 ); - meshBuilder.setCellCornersCount( 3, 5 ); - meshBuilder.setCellCornersCount( 4, 5 ); - meshBuilder.setCellCornersCount( 5, 5 ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( { 5, 5, 5, 5, 5, 5 } ); // Planar cell with non-deviated points meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); @@ -461,7 +441,8 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) PolygonTestMesh mesh; MeshBuilder< PolygonTestMesh > meshBuilder; - meshBuilder.setPointsCount( 16 ); + 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 ) ); @@ -491,15 +472,7 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) * 10 5 4 13 15 */ - meshBuilder.setCellsCount( 7 ); - meshBuilder.setCellCornersCount( 0, 6 ); - meshBuilder.setCellCornersCount( 1, 5 ); - meshBuilder.setCellCornersCount( 2, 4 ); - meshBuilder.setCellCornersCount( 3, 4 ); - meshBuilder.setCellCornersCount( 4, 5 ); - meshBuilder.setCellCornersCount( 5, 5 ); - meshBuilder.setCellCornersCount( 6, 5 ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( { 6, 5, 4, 4, 5, 5, 5 } ); // 1 0 3 2 4 5 meshBuilder.getCellSeed( 0 ).setCornerId( 0, 1 ); @@ -611,7 +584,8 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) PolyhedronTestMesh mesh; MeshBuilder< PolyhedronTestMesh > meshBuilder; - meshBuilder.setPointsCount( 22 ); + meshBuilder.setEntitiesCount( 22, 2, 16 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); @@ -658,24 +632,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) * NOTE: indeces refer to the points */ - meshBuilder.setFacesCount( 16 ); - meshBuilder.setFaceCornersCount( 0, 5 ); - meshBuilder.setFaceCornersCount( 1, 4 ); - meshBuilder.setFaceCornersCount( 2, 5 ); - meshBuilder.setFaceCornersCount( 3, 4 ); - meshBuilder.setFaceCornersCount( 4, 5 ); - meshBuilder.setFaceCornersCount( 5, 4 ); - meshBuilder.setFaceCornersCount( 6, 5 ); - meshBuilder.setFaceCornersCount( 7, 5 ); - meshBuilder.setFaceCornersCount( 8, 5 ); - meshBuilder.setFaceCornersCount( 9, 5 ); - meshBuilder.setFaceCornersCount( 10, 5 ); - meshBuilder.setFaceCornersCount( 11, 6 ); - meshBuilder.setFaceCornersCount( 12, 3 ); - meshBuilder.setFaceCornersCount( 13, 4 ); - meshBuilder.setFaceCornersCount( 14, 4 ); - meshBuilder.setFaceCornersCount( 15, 5 ); - meshBuilder.initializeFaceSeeds(); + 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 ); @@ -792,10 +749,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) * NOTE: indeces refer to the faces */ - meshBuilder.setCellsCount( 2 ); - meshBuilder.setCellCornersCount( 0, 9 ); - meshBuilder.setCellCornersCount( 1, 8 ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( { 9, 8 } ); // 0 1 2 3 4 5 6 7 8 meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); @@ -886,7 +840,8 @@ TEST( MeshGeometryTest, Polygon3DGetPlanarMeshTest ) PolygonTestMesh mesh; MeshBuilder< PolygonTestMesh > meshBuilder; - meshBuilder.setPointsCount( 6 ); + meshBuilder.setEntitiesCount( 6, 2 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); @@ -894,10 +849,7 @@ TEST( MeshGeometryTest, Polygon3DGetPlanarMeshTest ) meshBuilder.setPoint( 4, point4 ); meshBuilder.setPoint( 5, point5 ); - meshBuilder.setCellsCount( 2 ); - meshBuilder.setCellCornersCount( 0, 4 ); - meshBuilder.setCellCornersCount( 1, 4 ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( { 4, 4 } ); // Planar cell meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); @@ -972,7 +924,8 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) PolyhedronTestMesh mesh; MeshBuilder< PolyhedronTestMesh > meshBuilder; - meshBuilder.setPointsCount( 22 ); + meshBuilder.setEntitiesCount( 22, 2, 16 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); @@ -1019,24 +972,7 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) * NOTE: indeces refer to the points */ - meshBuilder.setFacesCount( 16 ); - meshBuilder.setFaceCornersCount( 0, 5 ); - meshBuilder.setFaceCornersCount( 1, 4 ); - meshBuilder.setFaceCornersCount( 2, 5 ); - meshBuilder.setFaceCornersCount( 3, 4 ); - meshBuilder.setFaceCornersCount( 4, 5 ); - meshBuilder.setFaceCornersCount( 5, 4 ); - meshBuilder.setFaceCornersCount( 6, 5 ); - meshBuilder.setFaceCornersCount( 7, 5 ); - meshBuilder.setFaceCornersCount( 8, 5 ); - meshBuilder.setFaceCornersCount( 9, 5 ); - meshBuilder.setFaceCornersCount( 10, 5 ); - meshBuilder.setFaceCornersCount( 11, 6 ); - meshBuilder.setFaceCornersCount( 12, 3 ); - meshBuilder.setFaceCornersCount( 13, 4 ); - meshBuilder.setFaceCornersCount( 14, 4 ); - meshBuilder.setFaceCornersCount( 15, 5 ); - meshBuilder.initializeFaceSeeds(); + 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 ); @@ -1153,10 +1089,7 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) * NOTE: indeces refer to the faces */ - meshBuilder.setCellsCount( 2 ); - meshBuilder.setCellCornersCount( 0, 9 ); - meshBuilder.setCellCornersCount( 1, 8 ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( { 9, 8 } ); // 0 1 2 3 4 5 6 7 8 meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); diff --git a/src/UnitTests/Meshes/MeshOrderingTest.h b/src/UnitTests/Meshes/MeshOrderingTest.h index 998e8b245..b06f9a9e1 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 96b2c3d69..bbeaf8684 100644 --- a/src/UnitTests/Meshes/MeshTest.h +++ b/src/UnitTests/Meshes/MeshTest.h @@ -196,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 ); @@ -285,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 ) ); @@ -324,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 ); @@ -458,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 @@ -559,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 @@ -693,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 @@ -1059,17 +1058,15 @@ TEST( MeshTest, TwoPolygonsTest ) PolygonTestMesh mesh; MeshBuilder< PolygonTestMesh > meshBuilder; - meshBuilder.setPointsCount( 5 ); + 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.setCellsCount( 2 ); - meshBuilder.setCellCornersCount( 0, 4 ); - meshBuilder.setCellCornersCount( 1, 3 ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( { 4, 3 } ); meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); @@ -1213,7 +1210,8 @@ TEST( MeshTest, SevenPolygonsTest ) PolygonTestMesh mesh; MeshBuilder< PolygonTestMesh > meshBuilder; - meshBuilder.setPointsCount( 16 ); + 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 ) ); @@ -1243,18 +1241,7 @@ TEST( MeshTest, SevenPolygonsTest ) * 10 5 4 13 15 */ - meshBuilder.setCellsCount( 7 ); - - meshBuilder.setCellsCount( 7 ); - meshBuilder.setCellCornersCount( 0, 6 ); - meshBuilder.setCellCornersCount( 1, 5 ); - meshBuilder.setCellCornersCount( 2, 4 ); - meshBuilder.setCellCornersCount( 3, 4 ); - meshBuilder.setCellCornersCount( 4, 5 ); - meshBuilder.setCellCornersCount( 5, 5 ); - meshBuilder.setCellCornersCount( 6, 5 ); - meshBuilder.initializeCellSeeds(); - + meshBuilder.setCellCornersCounts( { 6, 5, 4, 4, 5, 5, 5 } ); // 1 0 3 2 4 5 meshBuilder.getCellSeed( 0 ).setCornerId( 0, 1 ); @@ -1708,7 +1695,8 @@ TEST( MeshTest, TwoWedgesTest ) WedgeTestMesh mesh; MeshBuilder< WedgeTestMesh > meshBuilder; - meshBuilder.setPointsCount( 8 ); + meshBuilder.setEntitiesCount( 8, 2 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); @@ -1718,8 +1706,6 @@ TEST( MeshTest, TwoWedgesTest ) meshBuilder.setPoint( 6, point6 ); meshBuilder.setPoint( 7, point7 ); - meshBuilder.setCellsCount( 2 ); - meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -2182,7 +2168,8 @@ TEST( MeshTest, TwoPyramidsTest ) PyramidTestMesh mesh; MeshBuilder< PyramidTestMesh > meshBuilder; - meshBuilder.setPointsCount( 6 ); + meshBuilder.setEntitiesCount( 6, 2 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); @@ -2190,8 +2177,6 @@ TEST( MeshTest, TwoPyramidsTest ) meshBuilder.setPoint( 4, point4 ); meshBuilder.setPoint( 5, point5 ); - meshBuilder.setCellsCount( 2 ); - meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); meshBuilder.getCellSeed( 0 ).setCornerId( 1, 1 ); meshBuilder.getCellSeed( 0 ).setCornerId( 2, 2 ); @@ -2598,7 +2583,8 @@ TEST( MeshTest, TwoPolyhedronsTest ) PolyhedronTestMesh mesh; MeshBuilder< PolyhedronTestMesh > meshBuilder; - meshBuilder.setPointsCount( 22 ); + meshBuilder.setEntitiesCount( 22, 2, 16 ); + meshBuilder.setPoint( 0, point0 ); meshBuilder.setPoint( 1, point1 ); meshBuilder.setPoint( 2, point2 ); @@ -2645,24 +2631,7 @@ TEST( MeshTest, TwoPolyhedronsTest ) * NOTE: indeces refer to the points */ - meshBuilder.setFacesCount( 16 ); - meshBuilder.setFaceCornersCount( 0, 5 ); - meshBuilder.setFaceCornersCount( 1, 4 ); - meshBuilder.setFaceCornersCount( 2, 5 ); - meshBuilder.setFaceCornersCount( 3, 4 ); - meshBuilder.setFaceCornersCount( 4, 5 ); - meshBuilder.setFaceCornersCount( 5, 4 ); - meshBuilder.setFaceCornersCount( 6, 5 ); - meshBuilder.setFaceCornersCount( 7, 5 ); - meshBuilder.setFaceCornersCount( 8, 5 ); - meshBuilder.setFaceCornersCount( 9, 5 ); - meshBuilder.setFaceCornersCount( 10, 5 ); - meshBuilder.setFaceCornersCount( 11, 6 ); - meshBuilder.setFaceCornersCount( 12, 3 ); - meshBuilder.setFaceCornersCount( 13, 4 ); - meshBuilder.setFaceCornersCount( 14, 4 ); - meshBuilder.setFaceCornersCount( 15, 5 ); - meshBuilder.initializeFaceSeeds(); + 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 ); @@ -2779,10 +2748,7 @@ TEST( MeshTest, TwoPolyhedronsTest ) * NOTE: indeces refer to the faces */ - meshBuilder.setCellsCount( 2 ); - meshBuilder.setCellCornersCount( 0, 9 ); - meshBuilder.setCellCornersCount( 1, 8 ); - meshBuilder.initializeCellSeeds(); + meshBuilder.setCellCornersCounts( { 9, 8 } ); // 0 1 2 3 4 5 6 7 8 meshBuilder.getCellSeed( 0 ).setCornerId( 0, 0 ); diff --git a/src/UnitTests/Meshes/MeshTraverserTest.h b/src/UnitTests/Meshes/MeshTraverserTest.h index d0c16bfe4..af34d1f6f 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 -- GitLab From ec51a768ac70923dc8e669d6212c28c8d3c06dc8 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Tue, 14 Sep 2021 20:28:20 +0200 Subject: [PATCH 30/42] Extended mesh benchmark to measure time of copying mesh from CPU to GPU --- src/Benchmarks/Mesh/MeshBenchmarks.h | 94 +++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/src/Benchmarks/Mesh/MeshBenchmarks.h b/src/Benchmarks/Mesh/MeshBenchmarks.h index 96159eb44..1f54a998f 100644 --- a/src/Benchmarks/Mesh/MeshBenchmarks.h +++ b/src/Benchmarks/Mesh/MeshBenchmarks.h @@ -61,11 +61,11 @@ struct MeshBenchmarks Benchmark::MetadataColumns metadataColumns = { // {"mesh-file", meshFile}, {"config", Mesh::Config::getConfigType()}, - {"topology", removeNamespaces( getType< typename Mesh::Config::CellTopology >() ) }, + //{"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 >()} + //{"lid_t", getType< typename Mesh::LocalIndexType >()} }; const String & meshFile = parameters.getParameter< String >( "mesh-file" ); @@ -94,6 +94,7 @@ struct MeshBenchmarks PlanarDispatch::exec( benchmark, parameters, mesh ); MeasuresDispatch::exec( benchmark, parameters, mesh ); MemoryDispatch::exec( benchmark, parameters, mesh ); + CopyDispatch::exec( benchmark, parameters, mesh ); } struct ReaderDispatch @@ -303,6 +304,76 @@ struct MeshBenchmarks } }; + struct CopyDispatch + { + // 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 ) + { + benchmark.setOperation( String("Copy CPU->GPU") ); + exec_helper( benchmark, parameters, mesh ); + + { + benchmark.setOperation( String("Copy CPU->GPU (decomp (c))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Copy CPU->GPU (decomp (p))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + } + + // 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 ) + { + benchmark.setOperation( String("Copy CPU->GPU") ); + exec_helper( benchmark, parameters, mesh ); + + { + benchmark.setOperation( String("Copy CPU->GPU (decomp (cc))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Copy CPU->GPU (decomp (cp))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Copy CPU->GPU (decomp (pc))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + + { + benchmark.setOperation( String("Copy CPU->GPU (decomp (pp))") ); + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + exec_helper( benchmark, parameters, decomposedMesh ); + } + } + private: + template< typename M > + static void exec_helper( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh ) + { + //benchmark_copy< Devices::Host >( benchmark, parameters, mesh ); +#ifdef HAVE_CUDA + benchmark_copy< Devices::Cuda >( benchmark, parameters, mesh ); +#endif + } + }; + static void benchmark_reader( Benchmark & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) { auto reset = [&]() { @@ -428,6 +499,25 @@ struct MeshBenchmarks auto noop = [](){}; benchmark.time< TNL::Devices::Host >( "CPU", noop, memResult ); } + + template< typename Device, + typename M > + static void benchmark_copy( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + { + using DeviceMesh = Meshes::Mesh< typename M::Config, Device >; + + // skip benchmarks on devices which the user did not select + if( ! checkDevice< Device >( parameters ) ) + return; + + auto benchmark_func = [&] () { + DeviceMesh deviceMesh = mesh_src; + }; + + benchmark.time< Device >( [] () {}, + (std::is_same< Device, Devices::Host >::value) ? "CPU" : "GPU", + benchmark_func ); + } }; template< template< typename, int, typename, typename, typename > class ConfigTemplate, -- GitLab From 7aa6ed389389b8a783eae8ca9dd87fec0f286cff Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Sat, 18 Sep 2021 21:35:23 +0200 Subject: [PATCH 31/42] Added tools for mesh triangulation and planar correction and modified their unit tests --- src/TNL/Meshes/Geometry/getDecomposedMesh.h | 14 +- src/TNL/Meshes/Geometry/getPlanarMesh.h | 20 +-- src/Tools/CMakeLists.txt | 8 +- src/Tools/tnl-planar-correct-mesh.cpp | 171 ++++++++++++++++++++ src/Tools/tnl-triangulate-mesh.cpp | 171 ++++++++++++++++++++ src/UnitTests/Meshes/MeshGeometryTest.h | 132 ++++++--------- 6 files changed, 412 insertions(+), 104 deletions(-) create mode 100644 src/Tools/tnl-planar-correct-mesh.cpp create mode 100644 src/Tools/tnl-triangulate-mesh.cpp diff --git a/src/TNL/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h index af17a9d88..2a75772fc 100644 --- a/src/TNL/Meshes/Geometry/getDecomposedMesh.h +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -22,6 +22,7 @@ struct TriangleConfig: public ParentConfig }; 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 @@ -53,7 +54,7 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) const auto cell = inMesh.template getEntity< CellDimension >( i ); indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); }; - ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCounts ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCounts ); indeces[ 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 }; @@ -68,7 +69,7 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) auto copyPoint = [&] ( GlobalIndexType i ) mutable { meshBuilder.setPoint( i, inMesh.getPoint( i ) ); }; - ParallelFor< Devices::Host >::exec( 0, inPointsCount, copyPoint ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inPointsCount, copyPoint ); // Decompose each cell auto decomposeCell = [&] ( GlobalIndexType i ) mutable { @@ -94,12 +95,13 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) EntityDecomposer::decompose( cell, addPoint, addCell ); }; - ParallelFor< Devices::Host >::exec( 0, inCellsCount, decomposeCell ); + 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 @@ -154,7 +156,7 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) const auto cell = inMesh.template getEntity< CellDimension >( i ); indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); }; - ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCounts ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCounts ); indeces[ 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 }; @@ -169,7 +171,7 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) auto copyPoint = [&] ( GlobalIndexType i ) mutable { meshBuilder.setPoint( i, inMesh.getPoint( i ) ); }; - ParallelFor< Devices::Host >::exec( 0, inPointsCount, copyPoint ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inPointsCount, copyPoint ); // Decompose each cell auto decomposeCell = [&] ( GlobalIndexType i ) mutable { @@ -196,7 +198,7 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) EntityDecomposer::decompose( cell, addPoint, addCell ); }; - ParallelFor< Devices::Host >::exec( 0, inCellsCount, decomposeCell ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, decomposeCell ); return meshBuilder; } diff --git a/src/TNL/Meshes/Geometry/getPlanarMesh.h b/src/TNL/Meshes/Geometry/getPlanarMesh.h index aca91c073..8dba1133d 100644 --- a/src/TNL/Meshes/Geometry/getPlanarMesh.h +++ b/src/TNL/Meshes/Geometry/getPlanarMesh.h @@ -58,7 +58,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); } }; - ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCounts ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCounts ); indeces[ 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 }; @@ -73,7 +73,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) auto copyPoint = [&] ( GlobalIndexType i ) mutable { meshBuilder.setPoint( i, inMesh.getPoint( i ) ); }; - ParallelFor< Devices::Host >::exec( 0, inPointsCount, copyPoint ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inPointsCount, copyPoint ); // set corner counts for cells NeighborCountsArray cellCornersCounts( outCellsCount ); @@ -93,7 +93,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) } } }; - ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCornersCount ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCornersCount ); meshBuilder.setCellCornersCounts( std::move( cellCornersCounts ) ); // Decompose non-planar cells and copy the rest @@ -131,7 +131,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) EntityDecomposer::decompose( cell, addPoint, addCell ); } }; - ParallelFor< Devices::Host >::exec( 0, inCellsCount, decomposeCell ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, decomposeCell ); return meshBuilder; } @@ -179,7 +179,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( face ); } }; - ParallelFor< Devices::Host >::exec( 0, inFacesCount, setCounts ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inFacesCount, setCounts ); indeces[ 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 }; @@ -195,7 +195,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) auto copyPoint = [&] ( GlobalIndexType i ) mutable { meshBuilder.setPoint( i, inMesh.getPoint( i ) ); }; - ParallelFor< Devices::Host >::exec( 0, inPointsCount, copyPoint ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inPointsCount, copyPoint ); // set corner counts for cells NeighborCountsArray cellCornersCounts( outCellsCount ); @@ -212,7 +212,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) cellCornersCounts[ i ] = cornersCount; }; - ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCellCornersCount ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCellCornersCount ); meshBuilder.setCellCornersCounts( std::move( cellCornersCounts ) ); // Set corner ids for cells @@ -228,7 +228,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) } } }; - ParallelFor< Devices::Host >::exec( 0, inCellsCount, setCellCornersIds ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCellCornersIds ); // set corner counts for faces NeighborCountsArray faceCornersCounts( outFacesCount ); @@ -247,7 +247,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) } } }; - ParallelFor< Devices::Host >::exec( 0, inFacesCount, setFaceCornersCount ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inFacesCount, setFaceCornersCount ); meshBuilder.setFaceCornersCounts( std::move( faceCornersCounts ) ); // Decompose non-planar faces and copy the rest @@ -285,7 +285,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) EntityDecomposer::decompose( face, addPoint, addFace ); } }; - ParallelFor< Devices::Host >::exec( 0, inFacesCount, decomposeFace ); + ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inFacesCount, decomposeFace ); return meshBuilder; } diff --git a/src/Tools/CMakeLists.txt b/src/Tools/CMakeLists.txt index 84a05dd9c..8af2438fd 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-planar-correct-mesh.cpp b/src/Tools/tnl-planar-correct-mesh.cpp new file mode 100644 index 000000000..c4802b66a --- /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 000000000..092dd25ce --- /dev/null +++ b/src/Tools/tnl-triangulate-mesh.cpp @@ -0,0 +1,171 @@ +#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 ) }; }; + +// 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/MeshGeometryTest.h b/src/UnitTests/Meshes/MeshGeometryTest.h index 475a9b14a..6fa3ec1ee 100644 --- a/src/UnitTests/Meshes/MeshGeometryTest.h +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -524,30 +524,18 @@ TEST( MeshGeometryTest, PolygonDecompositionTest ) ASSERT_TRUE( meshBuilder.build( mesh ) ); - // Write original mesh + // Test for the 1st version { - using VTKWriter = Meshes::Writers::VTKWriter< decltype( mesh ) >; - std::ofstream file( "polygon_decompositionTest_orig.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( mesh ); + const auto triangleMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + EXPECT_EQ( triangleMesh.getEntitiesCount< 0 >(), 23 ); + EXPECT_EQ( triangleMesh.getEntitiesCount< 2 >(), 34 ); } - // Write decomposed mesh using 1st version + // Test for the 2nd version { - auto triangleMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( triangleMesh ) >; - std::ofstream file( "polygon_decompositionTest_c.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( triangleMesh ); - } - - // Write decomposed mesh using 2nd version - { - auto triangleMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( triangleMesh ) >; - std::ofstream file( "polygon_decompositionTest_p.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( triangleMesh ); + const auto triangleMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + EXPECT_EQ( triangleMesh.getEntitiesCount< 0 >(), 16 ); + EXPECT_EQ( triangleMesh.getEntitiesCount< 2 >(), 20 ); } } @@ -774,44 +762,36 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) ASSERT_TRUE( meshBuilder.build( mesh ) ); - // Write decomposed mesh using 1st version + // Test for the 1st version { - auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_decompositionTest_cc.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( tetrahedronMesh ); + const auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 0 >(), 40 ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 3 >(), 76 ); } - // Write decomposed mesh using 2nd version + // Test for the 2nd version { - auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_decompositionTest_cp.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( tetrahedronMesh ); + const auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 0 >(), 24 ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 3 >(), 44 ); } - // Write decomposed mesh using 3rd version + // Test for the 3rd version { - auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_decompositionTest_pc.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( tetrahedronMesh ); + const auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 0 >(), 32 ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 3 >(), 48 ); } - // Write decomposed mesh using 4th version + // Test for the 4th version { - auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_decompositionTest_pp.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( tetrahedronMesh ); + const auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 0 >(), 22 ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 3 >(), 28 ); } } @@ -872,22 +852,18 @@ TEST( MeshGeometryTest, Polygon3DGetPlanarMeshTest ) writer.template writeEntities( mesh ); } - // Write decomposed mesh using 1st version + // Test for the 1st version { - auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( planarMesh ) >; - std::ofstream file( "polygon_planarTest_c.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( planarMesh ); + const auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); + EXPECT_EQ( planarMesh.getEntitiesCount< 0 >(), 7 ); + EXPECT_EQ( planarMesh.getEntitiesCount< 2 >(), 5 ); } - // Write decomposed mesh using 2nd version + // Test for the 2nd version { - auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( planarMesh ) >; - std::ofstream file( "polygon_planarTest_p.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( planarMesh ); + const auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); + EXPECT_EQ( planarMesh.getEntitiesCount< 0 >(), 6 ); + EXPECT_EQ( planarMesh.getEntitiesCount< 2 >(), 3 ); } } @@ -1114,36 +1090,20 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) ASSERT_TRUE( meshBuilder.build( mesh ) ); - // Write original decomposed mesh - { - auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_planarTest_orig.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( tetrahedronMesh ); - } - - // Write planar decomposed mesh using 1st version + // Test for the 1st version { - auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToPoint >( planarMesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_planarTest_c.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( tetrahedronMesh ); + 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 ); } - // Write planar decomposed mesh using 2nd version + // Test for the 2nd version { - auto planarMesh = getPlanarMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToCentroid >( planarMesh ); - using VTKWriter = Meshes::Writers::VTKWriter< decltype( tetrahedronMesh ) >; - std::ofstream file( "polyhedron_planarTest_p.vtk" ); - VTKWriter writer( file, VTK::FileFormat::ascii ); - writer.template writeEntities( tetrahedronMesh ); + 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 ); } } -- GitLab From 020f80e854ab49cafa6672ecfc6bcbfd179b13bc Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Sun, 19 Sep 2021 18:59:56 +0200 Subject: [PATCH 32/42] Extended mesh benchmark to also measure time of copying mesh from GPU to CPU --- src/Benchmarks/Mesh/MeshBenchmarks.h | 85 +++++++++++++++++----------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/src/Benchmarks/Mesh/MeshBenchmarks.h b/src/Benchmarks/Mesh/MeshBenchmarks.h index 1f54a998f..841f9a21e 100644 --- a/src/Benchmarks/Mesh/MeshBenchmarks.h +++ b/src/Benchmarks/Mesh/MeshBenchmarks.h @@ -63,8 +63,8 @@ struct MeshBenchmarks {"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 >()}, + //{"real", getType< typename Mesh::RealType >()}, + //{"gid_t", getType< typename Mesh::GlobalIndexType >()}, //{"lid_t", getType< typename Mesh::LocalIndexType >()} }; @@ -309,67 +309,78 @@ struct MeshBenchmarks // 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 ) + static void exec( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { +#ifdef HAVE_CUDA benchmark.setOperation( String("Copy CPU->GPU") ); - exec_helper( benchmark, parameters, mesh ); + 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 ); { + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid>( mesh_src ); benchmark.setOperation( String("Copy CPU->GPU (decomp (c))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); + benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); + benchmark.setOperation( String("Copy GPU->CPU (decomp (c))") ); + benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); } { + const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); benchmark.setOperation( String("Copy CPU->GPU (decomp (p))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); + benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); + benchmark.setOperation( String("Copy GPU->CPU (decomp (p))") ); + benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); } +#endif } // 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 ) + static void exec( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { +#ifdef HAVE_CUDA benchmark.setOperation( String("Copy CPU->GPU") ); - exec_helper( benchmark, parameters, mesh ); + 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 ); { - benchmark.setOperation( String("Copy CPU->GPU (decomp (cc))") ); const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); + benchmark.setOperation( String("Copy CPU->GPU (decomp (cc))") ); + benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); + benchmark.setOperation( String("Copy GPU->CPU (decomp (cc))") ); + benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); } { - benchmark.setOperation( String("Copy CPU->GPU (decomp (cp))") ); const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh_src ); + benchmark.setOperation( String("Copy CPU->GPU (decomp (cp))") ); + benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); + benchmark.setOperation( String("Copy GPU->CPU (decomp (cp))") ); + benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); } { - benchmark.setOperation( String("Copy CPU->GPU (decomp (pc))") ); const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); + EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); + benchmark.setOperation( String("Copy CPU->GPU (decomp (pc))") ); + benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); + benchmark.setOperation( String("Copy GPU->CPU (decomp (pc))") ); + benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); } { - benchmark.setOperation( String("Copy CPU->GPU (decomp (pp))") ); const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); + EntityDecomposerVersion::ConnectEdgesToPoint >( mesh_src ); + benchmark.setOperation( String("Copy CPU->GPU (decomp (pp))") ); + benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); + benchmark.setOperation( String("Copy GPU->CPU (decomp (pp))") ); + benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); } - } - private: - template< typename M > - static void exec_helper( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh ) - { - //benchmark_copy< Devices::Host >( benchmark, parameters, mesh ); -#ifdef HAVE_CUDA - benchmark_copy< Devices::Cuda >( benchmark, parameters, mesh ); #endif } }; @@ -500,18 +511,26 @@ struct MeshBenchmarks benchmark.time< TNL::Devices::Host >( "CPU", noop, memResult ); } - template< typename Device, + template< typename DeviceFrom, + typename DeviceTo, typename M > static void benchmark_copy( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { - using DeviceMesh = Meshes::Mesh< typename M::Config, Device >; + 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 = [&] () { - DeviceMesh deviceMesh = mesh_src; + MeshTo meshTo = meshFrom; }; benchmark.time< Device >( [] () {}, -- GitLab From b449e89cebac87b5c84d65c102198542b802f783 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Sat, 25 Sep 2021 23:53:28 +0200 Subject: [PATCH 33/42] Refactoring for mesh initialization and unit tests - refactored a few for cycles in EntityInitializer to use ParallelFor - modified function findEntitySeedIndex in Initializer to use find instead of insert - modified FPMAReaderTest to use slightly bigger mesh for testing - added a few explanatory comments - deleted unused methods from SubentitySeedsCreator - created specialization of Formatter in Assert.h for std::pair to avoid compilation error caused by calling inplaceExclusiveScan on array of pairs --- src/Benchmarks/Mesh/MeshBenchmarks.h | 2 +- src/TNL/Assert.h | 19 +- src/TNL/Containers/UnorderedIndexedSet.hpp | 2 +- .../initializer/EntityInitializer.h | 62 +- .../MeshDetails/initializer/Initializer.h | 8 +- .../initializer/SubentitySeedsCreator.h | 155 +- .../Meshes/MeshDetails/traits/MeshTraits.h | 2 - src/TNL/Meshes/Readers/VTKReader.h | 5 +- src/UnitTests/Meshes/FPMAReaderTest.cpp | 8 +- src/UnitTests/Meshes/MeshGeometryTest.h | 2 +- .../polyhedrons/Poly_simple_corrected.fpma | 37 - .../Meshes/data/polyhedrons/cube1m_1.fpma | 5455 +++++++++++++++++ 12 files changed, 5538 insertions(+), 219 deletions(-) delete mode 100644 src/UnitTests/Meshes/data/polyhedrons/Poly_simple_corrected.fpma create mode 100644 src/UnitTests/Meshes/data/polyhedrons/cube1m_1.fpma diff --git a/src/Benchmarks/Mesh/MeshBenchmarks.h b/src/Benchmarks/Mesh/MeshBenchmarks.h index 841f9a21e..760775bb7 100644 --- a/src/Benchmarks/Mesh/MeshBenchmarks.h +++ b/src/Benchmarks/Mesh/MeshBenchmarks.h @@ -62,7 +62,7 @@ struct MeshBenchmarks // {"mesh-file", meshFile}, {"config", Mesh::Config::getConfigType()}, //{"topology", removeNamespaces( getType< typename Mesh::Config::CellTopology >() ) }, - {"space dim", std::to_string( Mesh::Config::spaceDimension )}, + //{"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 >()} diff --git a/src/TNL/Assert.h b/src/TNL/Assert.h index 06b68e33c..6bb28c9d0 100644 --- a/src/TNL/Assert.h +++ b/src/TNL/Assert.h @@ -217,13 +217,6 @@ fatalFailure() #endif } -template< typename T > -::std::stringstream& operator<<( ::std::stringstream& ss, const std::pair< T, T >& pair ) -{ - ss << '(' << pair.first << ',' << pair.second << ')'; - return ss; -} - template< typename T > struct Formatter { @@ -247,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.hpp b/src/TNL/Containers/UnorderedIndexedSet.hpp index a29aa2f4d..f48e055f4 100644 --- a/src/TNL/Containers/UnorderedIndexedSet.hpp +++ b/src/TNL/Containers/UnorderedIndexedSet.hpp @@ -84,7 +84,7 @@ 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; } diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h index 3ac007b72..268b9a1b1 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 { @@ -152,8 +154,10 @@ public: { NeighborCountsArray capacities( superentitiesCount ); - for( GlobalIndexType superentityIndex = 0; superentityIndex < capacities.getSize(); superentityIndex++ ) + 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 ); } @@ -163,15 +167,19 @@ public: superentitiesCounts.setSize( subentitiesCount ); superentitiesCounts.setValue( 0 ); - for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) + 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 ); - superentitiesCounts[ subentityIndex ]++; + + // SubentityIndeces 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 >(); @@ -179,7 +187,6 @@ public: matrix.setRowCapacities( superentitiesCounts ); superentitiesCounts.setValue( 0 ); - // initialize superentities storage for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; superentityIndex++ ) { for( LocalIndexType i = 0; @@ -333,18 +340,21 @@ public: { NeighborCountsArray capacities( superentitiesCount ); - for( GlobalIndexType superentityIndex = 0; superentityIndex < capacities.getSize(); superentityIndex++ ) + 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 ); - } - for( GlobalIndexType superentityIndex = 0; superentityIndex < superentitiesCount; 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 ); + 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 ); + }); }); } @@ -451,13 +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 ) { SubentitySeedsCreatorType::iterate( meshInitializer, mesh, superentityIndex, [&] ( SeedType& seed ) { const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( seed ); - superentitiesCounts[ subentityIndex ]++; + Algorithms::AtomicOperations< Devices::Host >::add( superentitiesCounts[ subentityIndex ], LocalIndexType{ 1 } ); }); - } + }); // allocate superentities storage SuperentityMatrixType& matrix = meshInitializer.template getSuperentitiesMatrix< SubdimensionTag::value, SuperdimensionTag::value >(); @@ -475,6 +485,24 @@ public: }); } + // 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 ); } }; diff --git a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h index aefbe2f72..9417c244e 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/Initializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/Initializer.h @@ -271,9 +271,11 @@ protected: } 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 ) @@ -309,6 +311,8 @@ protected: 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; diff --git a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h index b0c531ba9..b11c7c945 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h +++ b/src/TNL/Meshes/MeshDetails/initializer/SubentitySeedsCreator.h @@ -40,9 +40,9 @@ class SubentitySeedsCreator public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; - using SubentitySeedArray = Containers::StaticArray< SubentityTraits::count, SubentitySeed >; + //using SubentitySeedArray = Containers::StaticArray< SubentityTraits::count, SubentitySeed >; - static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + /*static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); @@ -63,14 +63,14 @@ public: ); 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, SubentitySeedArray::getSize() >( + Algorithms::staticFor< LocalIndexType, 0, SubentityTraits::count >( [&] ( auto subentityIndex ) { constexpr LocalIndexType subentityVerticesCount = Topologies::SubentityVertexCount< EntityTopology, SubentityTopology, subentityIndex >::count; SubentitySeed subentitySeed; @@ -110,7 +110,7 @@ public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; using SubentitySeedArray = Containers::StaticArray< SubentityTraits::count, SubentitySeed >; - static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) + /*static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) { const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); @@ -118,7 +118,7 @@ public: 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 ) @@ -154,26 +154,7 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 1 > public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; - using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; - static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) - { - const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); - const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); - - SubentitySeedArray seeds; - seeds.setSize( subverticesCount ); - - for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) - { - SubentitySeed& seed = seeds[ i ]; - seed.setCornerId( 0, subvertices.getColumnIndex( i ) ); - seed.setCornerId( 1, subvertices.getColumnIndex( (i + 1) % subverticesCount ) ); - } - - return seeds; - } - template< typename FunctorType > static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) { @@ -211,21 +192,6 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polygon, DimensionTag< 0 > public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; - using SubentitySeedArray = Containers::Array< SubentitySeed, Devices::Host, LocalIndexType >; - - static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) - { - const auto& subvertices = mesh.template getSubentitiesMatrix< EntityTopology::dimension, 0 >().getRow( entityIndex ); - const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< EntityTopology::dimension, 0 >( entityIndex ); - - SubentitySeedArray seeds; - seeds.setSize( subverticesCount ); - - 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 ) @@ -252,66 +218,19 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 2 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, 2 >; - using SubentityTopology = typename SubentityTraits::SubentityTopology; + using LocalIndexType = typename MeshTraitsType::LocalIndexType; public: - using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; - using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; - - static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) - { - const auto& cellSeeds = initializer.getCellSeeds(); - const auto faces = cellSeeds.getSeed( entityIndex ); - - SubentitySeedArray seeds; - seeds.setSize( faces.getCornersCount() ); - - for( LocalIndexType i = 0; i < seeds.getSize(); i++ ) - { - SubentitySeed& seed = seeds[ i ]; - GlobalIndexType faceIdx = faces.getCornerId( i ); - const auto& subvertices = mesh.template getSubentitiesMatrix< 2, 0 >().getRow( faceIdx ); - const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< 2, 0 >( faceIdx ); - seed.setCornersCount( subverticesCount ); - for( LocalIndexType j = 0; j < subverticesCount; j++ ) - { - seed.setCornerId( j, subvertices.getColumnIndex( j ) ); - } - } - - return seeds; - } - template< typename FunctorType > static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) { - const auto& cellSeeds = initializer.getCellSeeds(); - const auto faces = cellSeeds.getSeed( entityIndex ); - - for( LocalIndexType i = 0; i < faces.getCornersCount(); i++ ) - { - GlobalIndexType faceIdx = faces.getCornerId( i ); - const auto& subvertices = mesh.template getSubentitiesMatrix< 2, 0 >().getRow( faceIdx ); - const LocalIndexType subverticesCount = mesh.template getSubentitiesCount< 2, 0 >( faceIdx ); - SubentitySeed seed; - seed.setCornersCount( subverticesCount ); - for( LocalIndexType j = 0; j < subverticesCount; j++ ) { - seed.setCornerId( j, subvertices.getColumnIndex( j ) ); - } - std::forward< FunctorType >( functor )( seed ); - } + 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 ) { - const auto& cellSeeds = initializer.getCellSeeds(); - return cellSeeds.getSeed( entityIndex ).getCornersCount(); + throw std::logic_error{ "Subentities of dimension 2 for polyhedrons should be initialized from seeds." }; } }; @@ -333,35 +252,7 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 1 public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; - using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; - static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) - { - SubentitySeedArray seeds; - LocalIndexType subentitiesCount = getSubentitiesCount( initializer, mesh, entityIndex ); - seeds.setSize( subentitiesCount ); - GlobalIndexType seedsSize = 0; - - 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 ); - auto faceSubentitySeeds = FaceSubentitySeedsCreator::create( initializer, mesh, faceIdx ); - for( LocalIndexType j = 0; j < faceSubentitySeeds.getSize(); j++ ) - { - const auto& faceSubentitySeed = faceSubentitySeeds[ j ]; - bool inserted = seedSet.insert( faceSubentitySeed ).second; - if( inserted ) - seeds[ seedsSize++ ] = faceSubentitySeed; - } - } - - return seeds; - } - template< typename FunctorType > static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) { @@ -413,35 +304,7 @@ class SubentitySeedsCreator< MeshConfig, Topologies::Polyhedron, DimensionTag< 0 public: using SubentitySeed = EntitySeed< MeshConfig, SubentityTopology >; - using SubentitySeedArray = Containers::Array< SubentitySeed, DeviceType, LocalIndexType >; - static SubentitySeedArray create( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex ) - { - SubentitySeedArray seeds; - LocalIndexType subentitiesCount = getSubentitiesCount( initializer, mesh, entityIndex ); - seeds.setSize( subentitiesCount ); - GlobalIndexType seedsSize = 0; - - 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 ); - auto faceSubentitySeeds = FaceSubentitySeedsCreator::create( initializer, mesh, faceIdx ); - for( LocalIndexType j = 0; j < faceSubentitySeeds.getSize(); j++ ) - { - auto& faceSubentitySeed = faceSubentitySeeds[ j ]; - bool inserted = seedSet.insert( faceSubentitySeed ).second; - if( inserted ) - seeds[ seedsSize++ ] = faceSubentitySeed; - } - } - - return seeds; - } - template< typename FunctorType > static void iterate( InitializerType& initializer, MeshType& mesh, const GlobalIndexType entityIndex, FunctorType&& functor ) { diff --git a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h index 4f4d328f2..21e28b63f 100644 --- a/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h +++ b/src/TNL/Meshes/MeshDetails/traits/MeshTraits.h @@ -95,8 +95,6 @@ public: using NeighborCountsArray = Containers::Vector< LocalIndexType, DeviceType, GlobalIndexType >; using PointArrayType = Containers::Array< PointType, DeviceType, GlobalIndexType >; - using FaceSeedArrayType = Containers::Array< FaceSeedType, DeviceType, GlobalIndexType >; - using CellSeedArrayType = Containers::Array< CellSeedType, DeviceType, GlobalIndexType >; using FaceSeedMatrixType = EntitySeedMatrix< MeshConfig, FaceTopology >; using CellSeedMatrixType = EntitySeedMatrix< MeshConfig, CellTopology >; diff --git a/src/TNL/Meshes/Readers/VTKReader.h b/src/TNL/Meshes/Readers/VTKReader.h index 4e78d43e1..ccda6fc45 100644 --- a/src/TNL/Meshes/Readers/VTKReader.h +++ b/src/TNL/Meshes/Readers/VTKReader.h @@ -159,7 +159,7 @@ public: // validate cell types using PolygonShapeGroupChecker = VTK::EntityShapeGroupChecker< VTK::EntityShape::Polygon >; - //TODO: uncomment line below later for polyhedrals + //TODO: add EntityShapeGroup for polyhedrons and uncomment line below //using PolyhedralShapeGroupChecker = VTK::EntityShapeGroupChecker< VTK::EntityShape::Polyhedral >; cellShape = (VTK::EntityShape) cellTypes[0]; @@ -202,6 +202,9 @@ public: 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 indeces addressing created polygon subentities. if( entityShape == cellShape || PolygonShapeGroupChecker::bothBelong( cellShape, entityShape ) ) { iss.clear(); diff --git a/src/UnitTests/Meshes/FPMAReaderTest.cpp b/src/UnitTests/Meshes/FPMAReaderTest.cpp index 19aca53d2..bedfb05f7 100644 --- a/src/UnitTests/Meshes/FPMAReaderTest.cpp +++ b/src/UnitTests/Meshes/FPMAReaderTest.cpp @@ -32,15 +32,15 @@ template<> struct MeshCellTopologyTag< MyConfigTag, Topologies::Polyhedron > { e TEST( FPMAReaderTest, polyhedrons ) { using MeshType = Mesh< DefaultConfig< Topologies::Polyhedron > >; - const MeshType mesh = loadMeshFromFile< MeshType, Readers::FPMAReader >( "polyhedrons/Poly_simple_corrected.fpma" ); + 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, 22 ); - EXPECT_EQ( faces, 16 ); - EXPECT_EQ( cells, 2 ); + 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 ); diff --git a/src/UnitTests/Meshes/MeshGeometryTest.h b/src/UnitTests/Meshes/MeshGeometryTest.h index 6fa3ec1ee..2b6a1f03b 100644 --- a/src/UnitTests/Meshes/MeshGeometryTest.h +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -767,7 +767,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) const auto tetrahedronMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 0 >(), 40 ); - EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 3 >(), 76 ); + EXPECT_EQ( tetrahedronMesh.getEntitiesCount< 3 >(), 76 ); } // Test for the 2nd version diff --git a/src/UnitTests/Meshes/data/polyhedrons/Poly_simple_corrected.fpma b/src/UnitTests/Meshes/data/polyhedrons/Poly_simple_corrected.fpma deleted file mode 100644 index ccd2ad753..000000000 --- a/src/UnitTests/Meshes/data/polyhedrons/Poly_simple_corrected.fpma +++ /dev/null @@ -1,37 +0,0 @@ -# 22: number of vertices -22 -# vertex coordinates (x,y,z)-order --1.25 1.1665 1.203 -1.20683 1.16951 1.20537 -1.16843 1.19337 1.17878 -1.21025 1.21901 1.15383 -1.25 1.2128 1.1567 -1.20816 1.25 1.16756 -1.25 1.25 1.18056 -1.14802 1.21553 1.21165 -1.16186 1.25 1.21385 -1.20307 1.17486 1.25 -1.25 1.18056 1.25 -1.15677 1.22115 1.25 -1.18056 1.25 1.25 -1.25 1.25 1.25 -1.09277 1.20806 1.19263 -1.07219 1.22167 1.17994 -1.07215 1.25 1.18679 -1.05697 1.21124 1.19697 -1.04607 1.21508 1.22076 -1.0214 1.25 1.22293 -1.06418 1.22115 1.25 -1.04167 1.25 1.25 -# 16: number of faces -16 -# the first number means the number of vertices and the rest of numbers in the same line is vertex indicies attached to the face -5 0 1 2 3 4 -4 4 3 5 6 -5 5 3 2 7 8 -4 9 1 0 10 -5 11 7 2 1 9 -4 8 7 11 12 -5 13 12 11 9 10 -5 13 10 0 4 6 -5 13 6 5 8 12 -5 8 7 14 15 16 -5 16 15 17 18 19 -6 20 18 17 14 7 11 -3 17 15 14 -4 21 19 18 20 -4 21 20 11 12 -5 12 8 16 19 21 -# 2: number of cells -2 -# the first number means the number of faces and the rest of numbers in the same line are face indicies attached to the cell -9 0 1 2 3 4 5 6 7 8 -8 9 10 11 12 13 5 14 15 -# Additional information only, does contain topology information -# 1: The number of special selections, here there is only one selection named by boudary_face -1 -# boundary_face" is the name -boundary_face -# "3" means a boundary and "5" means 5 faces, and the last line is the face indices. You can see these faces in the figure, surrounded by green edges. -3 -5 -6 7 8 14 15 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 000000000..d53e228df --- /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 + + -- GitLab From 18b77cd160a123e7a67e806e58457ead38616a05 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Wed, 29 Sep 2021 13:28:17 +0200 Subject: [PATCH 34/42] Improved mesh benchmark to also support triangular and tetrahedral meshes --- src/Benchmarks/Mesh/MeshBenchmarks.h | 244 ++++------------------- src/Benchmarks/Mesh/tnl-benchmark-mesh.h | 4 + src/Tools/tnl-triangulate-mesh.cpp | 5 + 3 files changed, 50 insertions(+), 203 deletions(-) diff --git a/src/Benchmarks/Mesh/MeshBenchmarks.h b/src/Benchmarks/Mesh/MeshBenchmarks.h index 760775bb7..daf0e8ef6 100644 --- a/src/Benchmarks/Mesh/MeshBenchmarks.h +++ b/src/Benchmarks/Mesh/MeshBenchmarks.h @@ -150,12 +150,22 @@ struct MeshBenchmarks 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, bool > = true > + 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)" ) ); @@ -166,7 +176,9 @@ struct MeshBenchmarks } template< typename M, - std::enable_if_t< M::Config::spaceDimension < 3, bool > = true > + 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 ) { } @@ -174,219 +186,46 @@ struct MeshBenchmarks struct MeasuresDispatch { - // 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 ) - { - benchmark.setOperation( String("Measures") ); - exec_helper( benchmark, parameters, mesh ); - - { - benchmark.setOperation( String("Measures (decomp (c))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); - } - - { - benchmark.setOperation( String("Measures (decomp (p))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); - } - } - - // Polyhedral Mesh - template< typename M, - std::enable_if_t< std::is_same< typename M::Config::CellTopology, Topologies::Polyhedron >::value, bool > = true > + template< typename M > static void exec( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh ) { benchmark.setOperation( String("Measures") ); - exec_helper( benchmark, parameters, mesh ); - - { - benchmark.setOperation( String("Measures (decomp (cc))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); - } - - { - benchmark.setOperation( String("Measures (decomp (cp))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); - } - - { - benchmark.setOperation( String("Measures (decomp (pc))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); - } - - { - benchmark.setOperation( String("Measures (decomp (pp))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToPoint >( mesh ); - exec_helper( benchmark, parameters, decomposedMesh ); - } - } - private: - template< typename M > - static void exec_helper( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh ) - { benchmark_measures< Devices::Host >( benchmark, parameters, mesh ); -#ifdef HAVE_CUDA + #ifdef HAVE_CUDA benchmark_measures< Devices::Cuda >( benchmark, parameters, mesh ); -#endif + #endif } }; struct MemoryDispatch { - // Polygonal Mesh - template< typename M, - std::enable_if_t< std::is_same< typename M::Config::CellTopology, Topologies::Polygon >::value, bool > = true > + 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 ); - - { - benchmark.setOperation( String("Memory (decomp (c))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); - benchmark_memory( benchmark, parameters, decomposedMesh ); - } - - { - benchmark.setOperation( String("Memory (decomp (p))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint >( mesh_src ); - benchmark_memory( benchmark, parameters, decomposedMesh ); - } - } - - // 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("Memory") ); - benchmark_memory( benchmark, parameters, mesh_src ); - - { - benchmark.setOperation( String("Memory (decomp (cc))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); - benchmark_memory( benchmark, parameters, decomposedMesh ); - } - - - { - benchmark.setOperation( String("Memory (decomp (cp))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToPoint >( mesh_src ); - benchmark_memory( benchmark, parameters, decomposedMesh ); - } - - { - benchmark.setOperation( String("Memory (decomp (pc))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); - benchmark_memory( benchmark, parameters, decomposedMesh ); - } - - { - benchmark.setOperation( String("Memory (decomp (pp))") ); - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToPoint >( mesh_src ); - benchmark_memory( benchmark, parameters, decomposedMesh ); - } } }; struct CopyDispatch { - // 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 ) - { -#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 ); - - { - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid>( mesh_src ); - benchmark.setOperation( String("Copy CPU->GPU (decomp (c))") ); - benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); - benchmark.setOperation( String("Copy GPU->CPU (decomp (c))") ); - benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); - } - - { - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); - benchmark.setOperation( String("Copy CPU->GPU (decomp (p))") ); - benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); - benchmark.setOperation( String("Copy GPU->CPU (decomp (p))") ); - benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); - } -#endif - } - - // Polyhedral Mesh - template< typename M, - std::enable_if_t< std::is_same< typename M::Config::CellTopology, Topologies::Polyhedron >::value, bool > = true > + template< typename M > static void exec( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { -#ifdef HAVE_CUDA + #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 ); - - { - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); - benchmark.setOperation( String("Copy CPU->GPU (decomp (cc))") ); - benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); - benchmark.setOperation( String("Copy GPU->CPU (decomp (cc))") ); - benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); - } - - { - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToCentroid, - EntityDecomposerVersion::ConnectEdgesToPoint >( mesh_src ); - benchmark.setOperation( String("Copy CPU->GPU (decomp (cp))") ); - benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); - benchmark.setOperation( String("Copy GPU->CPU (decomp (cp))") ); - benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); - } - - { - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToCentroid >( mesh_src ); - benchmark.setOperation( String("Copy CPU->GPU (decomp (pc))") ); - benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); - benchmark.setOperation( String("Copy GPU->CPU (decomp (pc))") ); - benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); - } - - { - const auto decomposedMesh = getDecomposedMesh< EntityDecomposerVersion::ConnectEdgesToPoint, - EntityDecomposerVersion::ConnectEdgesToPoint >( mesh_src ); - benchmark.setOperation( String("Copy CPU->GPU (decomp (pp))") ); - benchmark_copy< Devices::Host, Devices::Cuda >( benchmark, parameters, decomposedMesh ); - benchmark.setOperation( String("Copy GPU->CPU (decomp (pp))") ); - benchmark_copy< Devices::Cuda, Devices::Host >( benchmark, parameters, decomposedMesh ); - } -#endif + #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(); }; @@ -402,6 +241,9 @@ struct MeshBenchmarks 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(); }; @@ -416,27 +258,15 @@ struct MeshBenchmarks benchmark_func ); } - // benchmark_decomposition (Polygonal Mesh) template< EntityDecomposerVersion DecomposerVersion, - typename M, - std::enable_if_t< std::is_same< typename M::Config::CellTopology, Topologies::Polygon >::value, bool > = true > + EntityDecomposerVersion SubDecomposerVersion = EntityDecomposerVersion::ConnectEdgesToPoint, + typename M > static void benchmark_decomposition( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { - auto benchmark_func = [&] () { - auto meshBuilder = decomposeMesh< DecomposerVersion >( mesh_src ); - }; - - benchmark.time< Devices::Host >( "CPU", - benchmark_func ); - } + // skip benchmarks on devices which the user did not select + if( ! checkDevice< Devices::Host >( parameters ) ) + return; - // benchmark_decomposition (Polyhedral Mesh) - template< EntityDecomposerVersion DecomposerVersion, - EntityDecomposerVersion SubDecomposerVersion, - typename M, - std::enable_if_t< std::is_same< typename M::Config::CellTopology, Topologies::Polyhedron >::value, bool > = true > - static void benchmark_decomposition( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) - { auto benchmark_func = [&] () { auto meshBuilder = decomposeMesh< DecomposerVersion, SubDecomposerVersion >( mesh_src ); }; @@ -447,9 +277,14 @@ struct MeshBenchmarks template< EntityDecomposerVersion DecomposerVersion, typename M, - std::enable_if_t< M::Config::spaceDimension == 3, bool > = true > + 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 ); }; @@ -506,6 +341,9 @@ struct MeshBenchmarks 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 ); diff --git a/src/Benchmarks/Mesh/tnl-benchmark-mesh.h b/src/Benchmarks/Mesh/tnl-benchmark-mesh.h index f814a32be..2ce4ab5e6 100644 --- a/src/Benchmarks/Mesh/tnl-benchmark-mesh.h +++ b/src/Benchmarks/Mesh/tnl-benchmark-mesh.h @@ -65,6 +65,10 @@ resolveCellTopology( Benchmark& benchmark, using VTK::EntityShape; switch( reader->getCellShape() ) { + case EntityShape::Triangle: + return setMeshParameters< Topologies::Triangle >( benchmark, metadata, parameters ); + case EntityShape::Tetra: + return setMeshParameters< Topologies::Tetrahedron >( benchmark, metadata, parameters ); case EntityShape::Polygon: switch( reader->getSpaceDimension() ) { diff --git a/src/Tools/tnl-triangulate-mesh.cpp b/src/Tools/tnl-triangulate-mesh.cpp index 092dd25ce..4c83b9794 100644 --- a/src/Tools/tnl-triangulate-mesh.cpp +++ b/src/Tools/tnl-triangulate-mesh.cpp @@ -30,6 +30,11 @@ 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 }; }; -- GitLab From e896d6506a4b181749b4bbd9478d8b4c97e5aeb9 Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Thu, 30 Sep 2021 20:52:14 +0200 Subject: [PATCH 35/42] Fixed CMakeList for mesh benchmark --- src/Benchmarks/Mesh/CMakeLists.txt | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Benchmarks/Mesh/CMakeLists.txt b/src/Benchmarks/Mesh/CMakeLists.txt index 02964bec2..b07ba5ef0 100644 --- a/src/Benchmarks/Mesh/CMakeLists.txt +++ b/src/Benchmarks/Mesh/CMakeLists.txt @@ -1,8 +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 ) -- GitLab From 4bd91113fb6a66224399a18b288d638f43de9e1a Mon Sep 17 00:00:00 2001 From: Jan Bobot Date: Fri, 1 Oct 2021 20:29:22 +0200 Subject: [PATCH 36/42] Slightly optimized polyhedron specialization of getEntityMeasure for cuda --- src/TNL/Meshes/Geometry/getEntityMeasure.h | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/TNL/Meshes/Geometry/getEntityMeasure.h b/src/TNL/Meshes/Geometry/getEntityMeasure.h index 649f90877..79fd31680 100644 --- a/src/TNL/Meshes/Geometry/getEntityMeasure.h +++ b/src/TNL/Meshes/Geometry/getEntityMeasure.h @@ -379,5 +379,32 @@ getEntityMeasure( const Mesh< MeshConfig, Device > & mesh, 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 -- GitLab From 1cb9a13481f3b4833565c68db09c3574cf23c633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Thu, 23 Dec 2021 13:44:54 +0100 Subject: [PATCH 37/42] Updated mesh benchmark to use the refactored interface of Benchmark See MR !107 --- src/Benchmarks/Mesh/MemoryInfo.h | 4 +- src/Benchmarks/Mesh/MeshBenchmarks.h | 49 ++++++++++++------------ src/Benchmarks/Mesh/tnl-benchmark-mesh.h | 31 ++++++--------- 3 files changed, 38 insertions(+), 46 deletions(-) diff --git a/src/Benchmarks/Mesh/MemoryInfo.h b/src/Benchmarks/Mesh/MemoryInfo.h index 2ac56ed5b..3325dde22 100644 --- a/src/Benchmarks/Mesh/MemoryInfo.h +++ b/src/Benchmarks/Mesh/MemoryInfo.h @@ -122,7 +122,7 @@ getSelfPhysicalMemory() } -#include +#include #include #include @@ -190,6 +190,6 @@ testMemoryUsage( const TNL::Config::ParameterContainer& parameters, 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 index daf0e8ef6..19a9ddda4 100644 --- a/src/Benchmarks/Mesh/MeshBenchmarks.h +++ b/src/Benchmarks/Mesh/MeshBenchmarks.h @@ -8,7 +8,7 @@ /* See Copyright Notice in tnl/Copyright */ -// Implemented by: Jakub Klinkovsky +// Implemented by: Ján Bobot, Jakub Klinkovský #pragma once @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include "MeshConfigs.h" #include "MemoryInfo.h" @@ -56,9 +56,9 @@ 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 ) + static bool run( Benchmark<> & benchmark, const Config::ParameterContainer & parameters ) { - Benchmark::MetadataColumns metadataColumns = { + Logging::MetadataColumns metadataColumns = { // {"mesh-file", meshFile}, {"config", Mesh::Config::getConfigType()}, //{"topology", removeNamespaces( getType< typename Mesh::Config::CellTopology >() ) }, @@ -67,6 +67,7 @@ struct MeshBenchmarks //{"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" ); @@ -80,13 +81,12 @@ struct MeshBenchmarks return false; } - benchmark.setMetadataColumns( metadataColumns ); dispatchTests( benchmark, parameters, mesh, reader ); return true; } - static void dispatchTests( Benchmark & benchmark, const Config::ParameterContainer & parameters, const Mesh & mesh, std::shared_ptr< MeshReader > reader ) + 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 ); @@ -99,7 +99,7 @@ struct MeshBenchmarks struct ReaderDispatch { - static void exec( Benchmark & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) { benchmark.setOperation( String( "Reader" ) ); benchmark_reader( benchmark, parameters, reader ); @@ -108,7 +108,7 @@ struct MeshBenchmarks struct InitDispatch { - static void exec( Benchmark & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) { benchmark.setOperation( String( "Init" ) ); benchmark_init( benchmark, parameters, reader ); @@ -120,7 +120,7 @@ struct MeshBenchmarks // 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 ) + 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 ); @@ -132,7 +132,7 @@ struct MeshBenchmarks // 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 ) + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { benchmark.setOperation( String( "Decomposition (cc)" ) ); benchmark_decomposition< EntityDecomposerVersion::ConnectEdgesToCentroid, @@ -155,7 +155,7 @@ struct MeshBenchmarks 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 ) + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { } }; @@ -166,7 +166,7 @@ struct MeshBenchmarks 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 ) + 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 ); @@ -179,7 +179,7 @@ struct MeshBenchmarks 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 ) + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { } }; @@ -187,7 +187,7 @@ struct MeshBenchmarks struct MeasuresDispatch { template< typename M > - static void exec( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh ) + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh ) { benchmark.setOperation( String("Measures") ); benchmark_measures< Devices::Host >( benchmark, parameters, mesh ); @@ -200,7 +200,7 @@ struct MeshBenchmarks struct MemoryDispatch { template< typename M > - static void exec( Benchmark& benchmark, const Config::ParameterContainer& parameters, const M& mesh_src ) + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer& parameters, const M& mesh_src ) { benchmark.setOperation( String("Memory") ); benchmark_memory( benchmark, parameters, mesh_src ); @@ -210,7 +210,7 @@ struct MeshBenchmarks struct CopyDispatch { template< typename M > - static void exec( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + static void exec( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { #ifdef HAVE_CUDA benchmark.setOperation( String("Copy CPU->GPU") ); @@ -221,7 +221,7 @@ struct MeshBenchmarks } }; - static void benchmark_reader( Benchmark & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) + static void benchmark_reader( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) { if( ! checkDevice< Devices::Host >( parameters ) ) return; @@ -239,7 +239,7 @@ struct MeshBenchmarks benchmark_func ); } - static void benchmark_init( Benchmark & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) + static void benchmark_init( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, std::shared_ptr< MeshReader > reader ) { if( ! checkDevice< Devices::Host >( parameters ) ) return; @@ -261,7 +261,7 @@ struct MeshBenchmarks template< EntityDecomposerVersion DecomposerVersion, EntityDecomposerVersion SubDecomposerVersion = EntityDecomposerVersion::ConnectEdgesToPoint, typename M > - static void benchmark_decomposition( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + 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 ) ) @@ -280,7 +280,7 @@ struct MeshBenchmarks 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 ) + static void benchmark_planar( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { if( ! checkDevice< Devices::Host >( parameters ) ) return; @@ -295,7 +295,7 @@ struct MeshBenchmarks template< typename Device, typename M > - static void benchmark_measures( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + static void benchmark_measures( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { using Real = typename M::RealType; using Index = typename M::GlobalIndexType; @@ -339,7 +339,7 @@ struct MeshBenchmarks } template< typename M > - static void benchmark_memory( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + static void benchmark_memory( Benchmark<> & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) { if( ! checkDevice< Devices::Host >( parameters ) ) return; @@ -352,7 +352,7 @@ struct MeshBenchmarks template< typename DeviceFrom, typename DeviceTo, typename M > - static void benchmark_copy( Benchmark & benchmark, const Config::ParameterContainer & parameters, const M & mesh_src ) + 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 >; @@ -386,8 +386,7 @@ template< template< typename, int, typename, typename, typename > class ConfigTe struct MeshBenchmarksRunner { static bool - run( Benchmark & benchmark, - Benchmark::MetadataMap metadata, + run( Benchmark<> & benchmark, const Config::ParameterContainer & parameters ) { using Config = ConfigTemplate< CellTopology, SpaceDimension, Real, GlobalIndex, LocalIndex >; diff --git a/src/Benchmarks/Mesh/tnl-benchmark-mesh.h b/src/Benchmarks/Mesh/tnl-benchmark-mesh.h index 2ce4ab5e6..56b3a866d 100644 --- a/src/Benchmarks/Mesh/tnl-benchmark-mesh.h +++ b/src/Benchmarks/Mesh/tnl-benchmark-mesh.h @@ -8,7 +8,7 @@ /* See Copyright Notice in tnl/Copyright */ -// Implemented by: Jakub Klinkovsky +// Implemented by: Ján Bobot, Jakub Klinkovský #pragma once @@ -38,14 +38,11 @@ setMeshParameters( Params&&... params ) } bool -resolveCellTopology( Benchmark& benchmark, - Benchmark::MetadataMap metadata, +resolveCellTopology( Benchmark<> & benchmark, const Config::ParameterContainer& parameters ) { const String & meshFile = parameters.getParameter< String >( "mesh-file" ); - benchmark.newBenchmark( meshFile, metadata ); - auto reader = getMeshReader( meshFile, "auto" ); try { @@ -66,22 +63,22 @@ resolveCellTopology( Benchmark& benchmark, switch( reader->getCellShape() ) { case EntityShape::Triangle: - return setMeshParameters< Topologies::Triangle >( benchmark, metadata, parameters ); + return setMeshParameters< Topologies::Triangle >( benchmark, parameters ); case EntityShape::Tetra: - return setMeshParameters< Topologies::Tetrahedron >( benchmark, metadata, parameters ); + return setMeshParameters< Topologies::Tetrahedron >( benchmark, parameters ); case EntityShape::Polygon: switch( reader->getSpaceDimension() ) { case 2: - return setMeshParameters< Topologies::Polygon, 2 >( benchmark, metadata, parameters ); + return setMeshParameters< Topologies::Polygon, 2 >( benchmark, parameters ); case 3: - return setMeshParameters< Topologies::Polygon, 3 >( benchmark, metadata, parameters ); + 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, metadata, parameters ); + return setMeshParameters< Topologies::Polyhedron >( benchmark, parameters ); default: std::cerr << "unsupported cell topology: " << getShapeName( reader->getCellShape() ) << std::endl; return false; @@ -138,18 +135,14 @@ main( int argc, char* argv[] ) std::ofstream logFile( logFileName.getString(), mode ); // init benchmark and common metadata - Benchmark benchmark( loops, verbose ); + Benchmark<> benchmark( logFile, loops, verbose ); - // prepare global metadata - Benchmark::MetadataMap metadata = getHardwareMetadata(); + // write global metadata into a separate file + std::map< std::string, std::string > metadata = getHardwareMetadata(); + writeMapAsJson( metadata, logFileName, ".metadata.json" ); - if( ! resolveCellTopology( benchmark, metadata, parameters ) ) + if( ! resolveCellTopology( benchmark, parameters ) ) return EXIT_FAILURE; - if( ! benchmark.save( logFile ) ) { - std::cerr << "Failed to write the benchmark results to file '" << parameters.getParameter< String >( "log-file" ) << "'." << std::endl; - return EXIT_FAILURE; - } - return EXIT_SUCCESS; } -- GitLab From c10637e85b0cde7b0d5c0a54160912114cc11a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Thu, 23 Dec 2021 15:18:09 +0100 Subject: [PATCH 38/42] Fixed tnl-decompose-mesh It was broken because the MeshBuilder interface was changed due to polygonal and polyhedral meshes, but tnl-decompose-mesh was not built on the CI due to a missing optional dependency (metis). --- src/Tools/tnl-decompose-mesh.cpp | 34 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/Tools/tnl-decompose-mesh.cpp b/src/Tools/tnl-decompose-mesh.cpp index 39612729b..97383e9f3 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 >; -- GitLab From 5e2e3758ac6234efec50555767271e8994aa6b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Thu, 23 Dec 2021 16:04:43 +0100 Subject: [PATCH 39/42] Fixed typos: indeces -> indices --- src/TNL/Algorithms/sort.h | 2 +- src/TNL/Meshes/Geometry/getDecomposedMesh.h | 38 +++++++------- src/TNL/Meshes/Geometry/getPlanarMesh.h | 50 +++++++++---------- .../initializer/EntityInitializer.h | 2 +- src/TNL/Meshes/Readers/VTKReader.h | 2 +- src/UnitTests/Meshes/MeshGeometryTest.h | 8 +-- src/UnitTests/Meshes/MeshTest.h | 4 +- 7 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/TNL/Algorithms/sort.h b/src/TNL/Algorithms/sort.h index 131561760..e5df3b276 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/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h index 2a75772fc..d5a370960 100644 --- a/src/TNL/Meshes/Geometry/getDecomposedMesh.h +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -40,27 +40,27 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) 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 indeces at which every cell will start writing new decomposed points and cells + // starting indices at which every cell will start writing new decomposed points and cells using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; - Array< IndexPair, Devices::Host > indeces( inCellsCount + 1 ); + Array< IndexPair, Devices::Host > indices( inCellsCount + 1 ); auto setCounts = [&] ( GlobalIndexType i ) { const auto cell = inMesh.template getEntity< CellDimension >( i ); - indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + indices[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); }; ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCounts ); - indeces[ inCellsCount ] = { 0, 0 }; // extend exclusive prefix sum by one element to also get result of reduce at the same time + 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( indeces, 0, indeces.getSize(), reduction, std::make_pair( 0, 0 ) ); - const auto& reduceResult = indeces[ inCellsCount ]; + 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 ); @@ -74,7 +74,7 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) // Decompose each cell auto decomposeCell = [&] ( GlobalIndexType i ) mutable { const auto cell = inMesh.template getEntity< CellDimension >( i ); - const auto& indexPair = indeces[ i ]; + const auto& indexPair = indices[ i ]; // Lambda for adding new points GlobalIndexType setPointIndex = inPointsCount + indexPair.first; @@ -109,7 +109,7 @@ 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 ); @@ -142,27 +142,27 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) 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 indeces at which every cell will start writing new decomposed points and cells + // starting indices at which every cell will start writing new decomposed points and cells using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; - Array< IndexPair, Devices::Host > indeces( inCellsCount + 1 ); + Array< IndexPair, Devices::Host > indices( inCellsCount + 1 ); auto setCounts = [&] ( GlobalIndexType i ) { const auto cell = inMesh.template getEntity< CellDimension >( i ); - indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + indices[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); }; ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCounts ); - indeces[ inCellsCount ] = { 0, 0 }; // extend exclusive prefix sum by one element to also get result of reduce at the same time + 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( indeces, 0, indeces.getSize(), reduction, std::make_pair( 0, 0 ) ); - const auto& reduceResult = indeces[ inCellsCount ]; + 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 ); @@ -176,7 +176,7 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) // Decompose each cell auto decomposeCell = [&] ( GlobalIndexType i ) mutable { const auto cell = inMesh.template getEntity< CellDimension >( i ); - const auto& indexPair = indeces[ i ]; + const auto& indexPair = indices[ i ]; // Lambda for adding new points GlobalIndexType setPointIndex = inPointsCount + indexPair.first; @@ -212,7 +212,7 @@ 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 ); @@ -220,4 +220,4 @@ getDecomposedMesh( const Mesh< MeshConfig, Devices::Host > & inMesh ) } } // namespace Meshes -} // namespace TNL \ No newline at end of file +} // namespace TNL diff --git a/src/TNL/Meshes/Geometry/getPlanarMesh.h b/src/TNL/Meshes/Geometry/getPlanarMesh.h index 8dba1133d..c26ebe66f 100644 --- a/src/TNL/Meshes/Geometry/getPlanarMesh.h +++ b/src/TNL/Meshes/Geometry/getPlanarMesh.h @@ -46,25 +46,25 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< CellDimension >(); // Find the number of output points and cells as well as - // starting indeces at which every cell will start writing new points and cells + // starting indices at which every cell will start writing new points and cells using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; - Array< IndexPair, Devices::Host > indeces( inCellsCount + 1 ); + Array< IndexPair, Devices::Host > indices( inCellsCount + 1 ); auto setCounts = [&] ( GlobalIndexType i ) { const auto cell = inMesh.template getEntity< CellDimension >( i ); if( isPlanar( inMesh, cell, precision ) ) { - indeces[ i ] = { 0, 1 }; // cell is not decomposed (0 extra points, 1 cell) + indices[ i ] = { 0, 1 }; // cell is not decomposed (0 extra points, 1 cell) } else { - indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); + indices[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( cell ); } }; ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inCellsCount, setCounts ); - indeces[ inCellsCount ] = { 0, 0 }; // extend exclusive prefix sum by one element to also get result of reduce at the same time + 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( indeces, 0, indeces.getSize(), reduction, std::make_pair( 0, 0 ) ); - const auto& reduceResult = indeces[ inCellsCount ]; + 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 ); @@ -78,8 +78,8 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) // set corner counts for cells NeighborCountsArray cellCornersCounts( outCellsCount ); auto setCornersCount = [&] ( GlobalIndexType i ) mutable { - GlobalIndexType cellIndex = indeces[ i ].second; - const GlobalIndexType nextCellIndex = indeces[ i + 1 ].second; + 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) @@ -99,8 +99,8 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) // Decompose non-planar cells and copy the rest auto decomposeCell = [&] ( GlobalIndexType i ) mutable { const auto cell = inMesh.template getEntity< CellDimension >( i ); - const auto& indexPair = indeces[ i ]; - const auto& nextIndexPair = indeces[ i + 1 ]; + 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) @@ -167,25 +167,25 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) const GlobalIndexType inCellsCount = inMesh.template getEntitiesCount< CellDimension >(); // Find the number of output points and faces as well as - // starting indeces at which every face will start writing new points and faces + // starting indices at which every face will start writing new points and faces using IndexPair = std::pair< GlobalIndexType, GlobalIndexType >; - Array< IndexPair, Devices::Host > indeces( inFacesCount + 1 ); + Array< IndexPair, Devices::Host > indices( inFacesCount + 1 ); auto setCounts = [&] ( GlobalIndexType i ) { const auto face = inMesh.template getEntity< FaceDimension >( i ); if( isPlanar( inMesh, face, precision ) ) { - indeces[ i ] = { 0, 1 }; // face is not decomposed (0 extra points, 1 face) + indices[ i ] = { 0, 1 }; // face is not decomposed (0 extra points, 1 face) } else { - indeces[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( face ); + indices[ i ] = EntityDecomposer::getExtraPointsAndEntitiesCount( face ); } }; ParallelFor< Devices::Host >::exec( GlobalIndexType{ 0 }, inFacesCount, setCounts ); - indeces[ inFacesCount ] = { 0, 0 }; // extend exclusive prefix sum by one element to also get result of reduce at the same time + 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( indeces, 0, indeces.getSize(), reduction, std::make_pair( 0, 0 ) ); - const auto& reduceResult = indeces[ inFacesCount ]; + 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 @@ -207,7 +207,7 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) LocalIndexType cornersCount = 0; for( LocalIndexType j = 0; j < cellFacesCount; j++ ) { const GlobalIndexType faceIdx = cell.template getSubentityIndex< FaceDimension >( j ); - cornersCount += indeces[ faceIdx + 1 ].second - indeces[ faceIdx ].second; + cornersCount += indices[ faceIdx + 1 ].second - indices[ faceIdx ].second; } cellCornersCounts[ i ] = cornersCount; @@ -222,8 +222,8 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) 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 = indeces[ faceIdx + 1 ].second; - for( GlobalIndexType k = indeces[ faceIdx ].second; k < endFaceIdx; k++ ) { + const GlobalIndexType endFaceIdx = indices[ faceIdx + 1 ].second; + for( GlobalIndexType k = indices[ faceIdx ].second; k < endFaceIdx; k++ ) { cellSeed.setCornerId( o++, k ); } } @@ -233,8 +233,8 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) // set corner counts for faces NeighborCountsArray faceCornersCounts( outFacesCount ); auto setFaceCornersCount = [&] ( GlobalIndexType i ) mutable { - GlobalIndexType faceIndex = indeces[ i ].second; - const GlobalIndexType nextFaceIndex = indeces[ i + 1 ].second; + 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 ); @@ -253,8 +253,8 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) // Decompose non-planar faces and copy the rest auto decomposeFace = [&] ( GlobalIndexType i ) mutable { const auto face = inMesh.template getEntity< FaceDimension >( i ); - const auto& indexPair = indeces[ i ]; - const auto& nextIndexPair = indeces[ i + 1 ]; + 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) diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h index 268b9a1b1..36d31fcd0 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntityInitializer.h @@ -173,7 +173,7 @@ public: SubentitySeedsCreatorType::iterate( meshInitializer, mesh, superentityIndex, [&] ( SeedType& seed ) { const GlobalIndexType subentityIndex = meshInitializer.findEntitySeedIndex( seed ); - // SubentityIndeces for SubdimensionTag::value == 0 of non-polyhedral meshes were already set up from seeds + // 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 ); diff --git a/src/TNL/Meshes/Readers/VTKReader.h b/src/TNL/Meshes/Readers/VTKReader.h index ccda6fc45..966e4f467 100644 --- a/src/TNL/Meshes/Readers/VTKReader.h +++ b/src/TNL/Meshes/Readers/VTKReader.h @@ -204,7 +204,7 @@ public: // 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 indeces addressing created polygon subentities. + // CellConnectivityArray and cellOffsetsArray will contain indices addressing created polygon subentities. if( entityShape == cellShape || PolygonShapeGroupChecker::bothBelong( cellShape, entityShape ) ) { iss.clear(); diff --git a/src/UnitTests/Meshes/MeshGeometryTest.h b/src/UnitTests/Meshes/MeshGeometryTest.h index 2b6a1f03b..146e04eaa 100644 --- a/src/UnitTests/Meshes/MeshGeometryTest.h +++ b/src/UnitTests/Meshes/MeshGeometryTest.h @@ -617,7 +617,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) * 21 20 11 12 * 12 8 16 19 21 * - * NOTE: indeces refer to the points + * NOTE: indices refer to the points */ meshBuilder.setFaceCornersCounts( { 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 6, 3, 4, 4, 5 } ); @@ -734,7 +734,7 @@ TEST( MeshGeometryTest, PolyhedronDecompositionTest ) * 0 1 2 3 4 5 6 7 8 * 9 10 11 12 13 5 14 15 * - * NOTE: indeces refer to the faces + * NOTE: indices refer to the faces */ meshBuilder.setCellCornersCounts( { 9, 8 } ); @@ -945,7 +945,7 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) * 21 20 11 12 * 12 8 16 19 21 * - * NOTE: indeces refer to the points + * NOTE: indices refer to the points */ meshBuilder.setFaceCornersCounts( { 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 6, 3, 4, 4, 5 } ); @@ -1062,7 +1062,7 @@ TEST( MeshGeometryTest, PolyhedronGetPlanarMeshTest ) * 0 1 2 3 4 5 6 7 8 * 9 10 11 12 13 5 14 15 * - * NOTE: indeces refer to the faces + * NOTE: indices refer to the faces */ meshBuilder.setCellCornersCounts( { 9, 8 } ); diff --git a/src/UnitTests/Meshes/MeshTest.h b/src/UnitTests/Meshes/MeshTest.h index bbeaf8684..b50e1f023 100644 --- a/src/UnitTests/Meshes/MeshTest.h +++ b/src/UnitTests/Meshes/MeshTest.h @@ -2628,7 +2628,7 @@ TEST( MeshTest, TwoPolyhedronsTest ) * 21 20 11 12 * 12 8 16 19 21 * - * NOTE: indeces refer to the points + * NOTE: indices refer to the points */ meshBuilder.setFaceCornersCounts( { 5, 4, 5, 4, 5, 4, 5, 5, 5, 5, 5, 6, 3, 4, 4, 5 } ); @@ -2745,7 +2745,7 @@ TEST( MeshTest, TwoPolyhedronsTest ) * 0 1 2 3 4 5 6 7 8 * 9 10 11 12 13 5 14 15 * - * NOTE: indeces refer to the faces + * NOTE: indices refer to the faces */ meshBuilder.setCellCornersCounts( { 9, 8 } ); -- GitLab From 8a424666bbc83010a52c0202ff354a9de5add11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Wed, 29 Dec 2021 09:48:33 +0100 Subject: [PATCH 40/42] Mesh: removed unused includes and type aliases from Geometry functions --- src/TNL/Meshes/Geometry/EntityDecomposer.h | 20 ++++++-------------- src/TNL/Meshes/Geometry/getDecomposedMesh.h | 2 -- src/TNL/Meshes/Geometry/getPlanarMesh.h | 1 - 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/TNL/Meshes/Geometry/EntityDecomposer.h b/src/TNL/Meshes/Geometry/EntityDecomposer.h index d15662ff8..268be58af 100644 --- a/src/TNL/Meshes/Geometry/EntityDecomposer.h +++ b/src/TNL/Meshes/Geometry/EntityDecomposer.h @@ -1,13 +1,10 @@ #pragma once -#include #include -#include #include #include +#include #include -#include -#include namespace TNL { namespace Meshes { @@ -19,7 +16,7 @@ enum class EntityDecomposerVersion template< typename MeshConfig, typename Topology, - EntityDecomposerVersion EntityDecomposerVersion_ = EntityDecomposerVersion::ConnectEdgesToCentroid, + EntityDecomposerVersion EntityDecomposerVersion_ = EntityDecomposerVersion::ConnectEdgesToCentroid, EntityDecomposerVersion SubentityDecomposerVersion = EntityDecomposerVersion::ConnectEdgesToCentroid > struct EntityDecomposer; @@ -31,10 +28,9 @@ struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersio using Topology = Topologies::Polygon; using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; - using PointType = typename VertexMeshEntityType::PointType; 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 >(); @@ -80,7 +76,6 @@ struct EntityDecomposer< MeshConfig, Topologies::Polygon, EntityDecomposerVersio using Topology = Topologies::Polygon; using MeshEntityType = MeshEntity< MeshConfig, Device, Topology >; using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; - using PointType = typename VertexMeshEntityType::PointType; using GlobalIndexType = typename MeshConfig::GlobalIndexType; using LocalIndexType = typename MeshConfig::LocalIndexType; @@ -116,11 +111,10 @@ struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVer using FaceTopology = Topologies::Polygon; using MeshEntityType = MeshEntity< MeshConfig, Device, CellTopology >; using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; - using PointType = typename VertexMeshEntityType::PointType; 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(); @@ -170,12 +164,10 @@ struct EntityDecomposer< MeshConfig, Topologies::Polyhedron, EntityDecomposerVer using MeshEntityType = MeshEntity< MeshConfig, Device, CellTopology >; using MeshSubentityType = MeshEntity< MeshConfig, Device, FaceTopology >; using VertexMeshEntityType = typename MeshEntityType::template SubentityTraits< 0 >::SubentityType; - using PointType = typename VertexMeshEntityType::PointType; using GlobalIndexType = typename MeshConfig::GlobalIndexType; using LocalIndexType = typename MeshConfig::LocalIndexType; - using RealType = typename MeshConfig::RealType; using SubentityDecomposer = EntityDecomposer< MeshConfig, FaceTopology, SubentityDecomposerVersion >; - + static std::pair< GlobalIndexType, GlobalIndexType > getExtraPointsAndEntitiesCount( const MeshEntityType& entity ) { const auto& mesh = entity.getMesh(); @@ -232,4 +224,4 @@ private: }; } // namespace Meshes -} // namespace TNL \ No newline at end of file +} // namespace TNL diff --git a/src/TNL/Meshes/Geometry/getDecomposedMesh.h b/src/TNL/Meshes/Geometry/getDecomposedMesh.h index d5a370960..d99d9ba8b 100644 --- a/src/TNL/Meshes/Geometry/getDecomposedMesh.h +++ b/src/TNL/Meshes/Geometry/getDecomposedMesh.h @@ -36,7 +36,6 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) using TriangleMesh = Mesh< TriangleMeshConfig, Devices::Host >; using MeshBuilder = MeshBuilder< TriangleMesh >; using GlobalIndexType = typename TriangleMesh::GlobalIndexType; - using LocalIndexType = typename TriangleMesh::LocalIndexType; using PointType = typename TriangleMesh::PointType; using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, DecomposerVersion >; constexpr int CellDimension = TriangleMesh::getMeshDimension(); @@ -138,7 +137,6 @@ decomposeMesh( const Mesh< MeshConfig, Devices::Host >& inMesh ) using TetrahedronMesh = Mesh< TetrahedronMeshConfig, Devices::Host >; using MeshBuilder = MeshBuilder< TetrahedronMesh >; using GlobalIndexType = typename TetrahedronMesh::GlobalIndexType; - using LocalIndexType = typename TetrahedronMesh::LocalIndexType; using PointType = typename TetrahedronMesh::PointType; using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polyhedron, DecomposerVersion, SubdecomposerVersion >; constexpr int CellDimension = TetrahedronMesh::getMeshDimension(); diff --git a/src/TNL/Meshes/Geometry/getPlanarMesh.h b/src/TNL/Meshes/Geometry/getPlanarMesh.h index c26ebe66f..f32e5da97 100644 --- a/src/TNL/Meshes/Geometry/getPlanarMesh.h +++ b/src/TNL/Meshes/Geometry/getPlanarMesh.h @@ -34,7 +34,6 @@ planarCorrection( const Mesh< MeshConfig, Devices::Host >& inMesh ) using LocalIndexType = typename PolygonMesh::LocalIndexType; using PointType = typename PolygonMesh::PointType; using RealType = typename PolygonMesh::RealType; - using BoolVector = Containers::Vector< bool, Devices::Host, GlobalIndexType >; using EntityDecomposer = EntityDecomposer< MeshConfig, Topologies::Polygon, DecomposerVersion >; constexpr int CellDimension = PolygonMesh::getMeshDimension(); -- GitLab From 8db5d2da032ef96ac9d1681ece6eea6306c8433f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Wed, 29 Dec 2021 22:30:57 +0100 Subject: [PATCH 41/42] Refactored constructors and assignment operators in EntitySeedMatrix specializations --- .../initializer/EntitySeedMatrix.h | 46 ++++++++----------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h index 4dd2f9a3f..ae6ac5eed 100644 --- a/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h +++ b/src/TNL/Meshes/MeshDetails/initializer/EntitySeedMatrix.h @@ -30,15 +30,13 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, false > EntitySeedMatrix() = default; - EntitySeedMatrix( const EntitySeedMatrix& other ) - { - this->matrix = other.matrix; - } + EntitySeedMatrix( const EntitySeedMatrix& other ) = default; - EntitySeedMatrix( EntitySeedMatrix&& other ) - { - this->matrix = std::move( other.matrix ); - } + EntitySeedMatrix( EntitySeedMatrix&& other ) = default; + + EntitySeedMatrix& operator=( const EntitySeedMatrix& other ) = default; + + EntitySeedMatrix& operator=( EntitySeedMatrix&& other ) = default; class EntitySeedMatrixSeed { @@ -172,15 +170,13 @@ class EntitySeedMatrix< MeshConfig, Topologies::Vertex, false > EntitySeedMatrix() = default; - EntitySeedMatrix( const EntitySeedMatrix& other ) - { - this->matrix = other.matrix; - } + EntitySeedMatrix( const EntitySeedMatrix& other ) = default; - EntitySeedMatrix( EntitySeedMatrix&& other ) - { - this->matrix = std::move( other.matrix ); - } + EntitySeedMatrix( EntitySeedMatrix&& other ) = default; + + EntitySeedMatrix& operator=( const EntitySeedMatrix& other ) = default; + + EntitySeedMatrix& operator=( EntitySeedMatrix&& other ) = default; class EntitySeedMatrixSeed { @@ -315,17 +311,13 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, true > EntitySeedMatrix() = default; - EntitySeedMatrix( const EntitySeedMatrix& other ) - { - this->matrix = other.matrix; - this->counts = other.counts; - } + EntitySeedMatrix( const EntitySeedMatrix& other ) = default; - EntitySeedMatrix( EntitySeedMatrix&& other ) - { - this->matrix = std::move( other.matrix ); - this->counts = std::move( other.counts ); - } + EntitySeedMatrix( EntitySeedMatrix&& other ) = default; + + EntitySeedMatrix& operator=( const EntitySeedMatrix& other ) = default; + + EntitySeedMatrix& operator=( EntitySeedMatrix&& other ) = default; class EntitySeedMatrixSeed { @@ -455,4 +447,4 @@ class EntitySeedMatrix< MeshConfig, EntityTopology, true > }; } // namespace Meshes -} // namespace TNL \ No newline at end of file +} // namespace TNL -- GitLab From 0596330e7150abfce0a35bf37d39f982803abf24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Thu, 30 Dec 2021 21:35:07 +0100 Subject: [PATCH 42/42] Fixed move-semantics in Mesh and its subclasses --- src/TNL/Meshes/Mesh.h | 6 +- src/TNL/Meshes/Mesh.hpp | 13 +--- .../MeshDetails/layers/DualGraphLayer.h | 9 +-- .../MeshDetails/layers/EntityTags/Layer.h | 28 ++----- .../layers/EntityTags/LayerFamily.h | 22 +++--- .../Meshes/MeshDetails/layers/StorageLayer.h | 43 ++++------- .../layers/SubentityStorageLayer.h | 77 ++++++++----------- .../layers/SuperentityStorageLayer.h | 22 +++--- 8 files changed, 85 insertions(+), 135 deletions(-) diff --git a/src/TNL/Meshes/Mesh.h b/src/TNL/Meshes/Mesh.h index 2513982f3..808830904 100644 --- a/src/TNL/Meshes/Mesh.h +++ b/src/TNL/Meshes/Mesh.h @@ -93,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 ); diff --git a/src/TNL/Meshes/Mesh.hpp b/src/TNL/Meshes/Mesh.hpp index c928783f4..efb2b432d 100644 --- a/src/TNL/Meshes/Mesh.hpp +++ b/src/TNL/Meshes/Mesh.hpp @@ -59,17 +59,6 @@ Mesh( const Mesh< MeshConfig, Device_ >& mesh ) points = mesh.getPoints(); } -template< typename MeshConfig, typename Device > -Mesh< MeshConfig, Device >& -Mesh< MeshConfig, Device >:: -operator=( const Mesh& mesh ) -{ - points = mesh.getPoints(); - StorageBaseType::operator=( mesh ); - EntityTagsLayerFamily::operator=( mesh ); - return *this; -} - template< typename MeshConfig, typename Device > template< typename Device_ > Mesh< MeshConfig, Device >& @@ -114,7 +103,7 @@ getEntity( const GlobalIndexType entityIndex ) const template< typename MeshConfig, typename Device > template< int Dimension > void -Mesh< MeshConfig, Device >:: +Mesh< MeshConfig, Device >:: setEntitiesCount( const typename MeshTraitsType::GlobalIndexType& entitiesCount ) { StorageBaseType::setEntitiesCount( DimensionTag< Dimension >(), entitiesCount ); diff --git a/src/TNL/Meshes/MeshDetails/layers/DualGraphLayer.h b/src/TNL/Meshes/MeshDetails/layers/DualGraphLayer.h index 3ca05fc00..0292ccd53 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 b722535a5..985541c1b 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 712bee34e..de0bac7c6 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 84f312834..6d88caaa6 100644 --- a/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/StorageLayer.h @@ -52,10 +52,9 @@ class StorageLayerFamily 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 ) @@ -63,12 +62,9 @@ public: operator=( other ); } - StorageLayerFamily& operator=( const StorageLayerFamily& layer ) - { - 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 ) @@ -224,10 +220,7 @@ public: 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 ) @@ -235,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 ) @@ -303,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 31cd80a18..0cefa9d15 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SubentityStorageLayer.h @@ -120,10 +120,9 @@ protected: SubentityStorageLayer() = default; - explicit SubentityStorageLayer( const SubentityStorageLayer& other ) - { - operator=( other ); - } + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer( SubentityStorageLayer&& other ) = default; template< typename Device_ > SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) @@ -131,12 +130,9 @@ protected: operator=( other ); } - SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) - { - BaseType::operator=( other ); - matrix = other.matrix; - return *this; - } + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer& operator=( SubentityStorageLayer&& other ) = default; template< typename Device_ > SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) @@ -225,10 +221,9 @@ protected: SubentityStorageLayer() = default; - explicit SubentityStorageLayer( const SubentityStorageLayer& other ) - { - operator=( other ); - } + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer( SubentityStorageLayer&& other ) = default; template< typename Device_ > SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) @@ -236,13 +231,9 @@ protected: operator=( other ); } - SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) - { - BaseType::operator=( other ); - subentitiesCounts = other.subentitiesCounts; - matrix = other.matrix; - return *this; - } + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer& operator=( SubentityStorageLayer&& other ) = default; template< typename Device_ > SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) @@ -315,7 +306,7 @@ 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_, bool dynamicTopology_ > friend class SubentityStorageLayer; @@ -350,10 +341,9 @@ protected: SubentityStorageLayer() = default; - explicit SubentityStorageLayer( const SubentityStorageLayer& other ) - { - operator=( other ); - } + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer( SubentityStorageLayer&& other ) = default; template< typename Device_ > SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) @@ -361,13 +351,9 @@ protected: operator=( other ); } - SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) - { - BaseType::operator=( other ); - subentitiesCounts = other.subentitiesCounts; - matrix = other.matrix; - return *this; - } + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer& operator=( SubentityStorageLayer&& other ) = default; template< typename Device_ > SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) @@ -434,7 +420,7 @@ 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_, bool dynamicTopology_ > friend class SubentityStorageLayer; @@ -469,10 +455,9 @@ protected: SubentityStorageLayer() = default; - explicit SubentityStorageLayer( const SubentityStorageLayer& other ) - { - operator=( other ); - } + explicit SubentityStorageLayer( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer( SubentityStorageLayer&& other ) = default; template< typename Device_ > SubentityStorageLayer( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) @@ -480,12 +465,9 @@ protected: operator=( other ); } - SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) - { - BaseType::operator=( other ); - matrix = other.matrix; - return *this; - } + SubentityStorageLayer& operator=( const SubentityStorageLayer& other ) = default; + + SubentityStorageLayer& operator=( SubentityStorageLayer&& other ) = default; template< typename Device_ > SubentityStorageLayer& operator=( const SubentityStorageLayer< MeshConfig, Device_, EntityTopology, SubdimensionTag >& other ) @@ -533,7 +515,7 @@ protected: 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; @@ -584,9 +566,12 @@ 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; } diff --git a/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h b/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h index 4a15cf19e..5a802735c 100644 --- a/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h +++ b/src/TNL/Meshes/MeshDetails/layers/SuperentityStorageLayer.h @@ -105,10 +105,9 @@ 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_, EntityDimensionTag, SuperdimensionTag >& other ) @@ -116,13 +115,9 @@ protected: 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_, EntityDimensionTag, SuperdimensionTag >& other ) @@ -208,9 +203,12 @@ class SuperentityStorageLayer< MeshConfig, Device, EntityDimensionTag, EntityDim 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_, EntityDimensionTag, SuperdimensionTag >& other ) {} + SuperentityStorageLayer& operator=( const SuperentityStorageLayer& other ) = default; + SuperentityStorageLayer& operator=( SuperentityStorageLayer&& other ) = default; template< typename Device_ > SuperentityStorageLayer& operator=( const SuperentityStorageLayer< MeshConfig, Device_, EntityDimensionTag, SuperdimensionTag >& other ) { return *this; } -- GitLab