Loading src/TNL/Meshes/Mesh.h +6 −11 Original line number Diff line number Diff line Loading @@ -20,15 +20,15 @@ #include <TNL/Object.h> #include <TNL/Logger.h> #include <TNL/Meshes/MeshEntity.h> #include <TNL/Meshes/MeshDetails/ConfigValidator.h> #include <TNL/Meshes/MeshDetails/traits/MeshTraits.h> #include <TNL/Meshes/MeshDetails/MeshLayers/StorageLayer.h> #include <TNL/Meshes/MeshDetails/ConfigValidator.h> #include <TNL/Meshes/MeshDetails/MeshLayers/BoundaryTags/LayerFamily.h> namespace TNL { namespace Meshes { template< typename MeshConfig > class Initializer; template< typename Mesh > class BoundaryTagsInitializer; template< typename Mesh > class EntityStorageRebinder; template< typename Mesh, int Dimension > struct IndexPermutationApplier; Loading Loading @@ -56,10 +56,12 @@ template< typename MeshConfig, class Mesh : public Object, public ConfigValidator< MeshConfig >, protected StorageLayerFamily< MeshConfig, Device >, public MeshInitializableBase< MeshConfig, Device, Mesh< MeshConfig, Device > > public MeshInitializableBase< MeshConfig, Device, Mesh< MeshConfig, Device > >, public StorageLayerFamily< MeshConfig, Device >, public BoundaryTags::LayerFamily< MeshConfig, Device, Mesh< MeshConfig, Device > > { using StorageBaseType = StorageLayerFamily< MeshConfig, Device >; using BoundaryTagsLayerFamily = BoundaryTags::LayerFamily< MeshConfig, Device, Mesh >; public: using Config = MeshConfig; Loading Loading @@ -110,11 +112,6 @@ class Mesh virtual String getSerializationTypeVirtual() const; using StorageBaseType::isBoundaryEntity; using StorageBaseType::getBoundaryEntitiesCount; using StorageBaseType::getBoundaryEntityIndex; using StorageBaseType::getInteriorEntitiesCount; using StorageBaseType::getInteriorEntityIndex; template< int Dimension > static constexpr bool entitiesAvailable(); Loading Loading @@ -180,8 +177,6 @@ class Mesh friend Initializer< MeshConfig >; friend BoundaryTagsInitializer< Mesh >; friend EntityStorageRebinder< Mesh >; template< typename Mesh, int Dimension > Loading src/TNL/Meshes/MeshDetails/ConfigValidator.h +6 −30 Original line number Diff line number Diff line Loading @@ -71,28 +71,6 @@ class ConfigValidatorSupertopologyLayer< MeshConfig, EntityTopology, DimensionTa {}; template< typename MeshConfig, typename EntityTopology, bool BoundaryTagsStorage = MeshConfig::boundaryTagsStorage( EntityTopology() ) > class ConfigValidatorBoundaryTagsLayer { using FaceTopology = typename Topologies::Subtopology< typename MeshConfig::CellTopology, MeshConfig::meshDimension - 1 >::Topology; static_assert( MeshConfig::entityStorage( MeshConfig::meshDimension - 1 ), "Faces must be stored when any entity has boundary tags." ); static_assert( MeshConfig::superentityStorage( FaceTopology(), MeshConfig::meshDimension ), "Faces must store the cell superentity indices when any entity has boundary tags." ); static_assert( EntityTopology::dimension >= MeshConfig::meshDimension - 1 || MeshConfig::subentityStorage( FaceTopology(), EntityTopology::dimension ), "Faces must store the subentity indices of the entities on which the boundary tags are stored." ); }; template< typename MeshConfig, typename EntityTopology > class ConfigValidatorBoundaryTagsLayer< MeshConfig, EntityTopology, false > { }; template< typename MeshConfig, int dimension > class ConfigValidatorLayer : public ConfigValidatorLayer< MeshConfig, dimension - 1 >, Loading @@ -101,9 +79,7 @@ class ConfigValidatorLayer DimensionTag< dimension - 1 > >, public ConfigValidatorSupertopologyLayer< MeshConfig, typename Topologies::Subtopology< typename MeshConfig::CellTopology, dimension >::Topology, DimensionTag< MeshConfig::CellTopology::dimension > >, public ConfigValidatorBoundaryTagsLayer< MeshConfig, typename Topologies::Subtopology< typename MeshConfig::CellTopology, dimension >::Topology > DimensionTag< MeshConfig::CellTopology::dimension > > { using Topology = typename Topologies::Subtopology< typename MeshConfig::CellTopology, dimension >::Topology; Loading src/TNL/Meshes/MeshDetails/MeshLayers/BoundaryTags/CMakeLists.txt 0 → 100644 +8 −0 Original line number Diff line number Diff line SET( headers ConfigValidator.h Layer.h LayerFamily.h Initializer.h Traits.h ) INSTALL( FILES ${headers} DESTINATION include/tnl-${tnlVersion}/TNL/Meshes/MeshDetails/MeshLayers/BoundaryTags ) src/TNL/Meshes/MeshDetails/MeshLayers/BoundaryTags/ConfigValidator.h 0 → 100644 +63 −0 Original line number Diff line number Diff line /*************************************************************************** ConfigValidator.h - description ------------------- begin : Aug 14, 2015 copyright : (C) 2015 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ #pragma once #include <TNL/Meshes/Topologies/SubentityVertexMap.h> #include <TNL/Meshes/MeshDetails/traits/MeshTraits.h> namespace TNL { namespace Meshes { namespace BoundaryTags { template< typename MeshConfig, typename EntityTopology, bool BoundaryTagsStorage = MeshConfig::boundaryTagsStorage( EntityTopology() ) > class ConfigValidatorBoundaryTagsLayer { using FaceTopology = typename Topologies::Subtopology< typename MeshConfig::CellTopology, MeshConfig::meshDimension - 1 >::Topology; static_assert( MeshConfig::entityStorage( MeshConfig::meshDimension - 1 ), "Faces must be stored when any entity has boundary tags." ); static_assert( MeshConfig::superentityStorage( FaceTopology(), MeshConfig::meshDimension ), "Faces must store the cell superentity indices when any entity has boundary tags." ); static_assert( EntityTopology::dimension >= MeshConfig::meshDimension - 1 || MeshConfig::subentityStorage( FaceTopology(), EntityTopology::dimension ), "Faces must store the subentity indices of the entities on which the boundary tags are stored." ); }; template< typename MeshConfig, typename EntityTopology > class ConfigValidatorBoundaryTagsLayer< MeshConfig, EntityTopology, false > { }; template< typename MeshConfig, int dimension = MeshConfig::meshDimension > class ConfigValidatorLayer : public ConfigValidatorLayer< MeshConfig, dimension - 1 >, public ConfigValidatorBoundaryTagsLayer< MeshConfig, typename MeshTraits< MeshConfig >::template EntityTraits< dimension >::EntityTopology > { }; template< typename MeshConfig > class ConfigValidatorLayer< MeshConfig, 0 > { }; template< typename MeshConfig > class ConfigValidator : public ConfigValidatorLayer< MeshConfig > { }; } // namespace BoundaryTags } // namespace Meshes } // namespace TNL src/TNL/Meshes/MeshDetails/initializer/BoundaryTagsInitializer.h→src/TNL/Meshes/MeshDetails/MeshLayers/BoundaryTags/Initializer.h +30 −20 Original line number Diff line number Diff line /*************************************************************************** BoundaryTagsInitializer.h - description Initializer.h - description ------------------- begin : Dec 26, 2016 copyright : (C) 2016 by Tomas Oberhuber et al. Loading @@ -14,36 +14,44 @@ #include <TNL/ParallelFor.h> #include <TNL/DevicePointer.h> #include <TNL/Meshes/DimensionTag.h> #include <TNL/Meshes/MeshDetails/traits/MeshTraits.h> #include <TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h> namespace TNL { namespace Meshes { namespace BoundaryTags { template< typename Mesh > class BoundaryTagsInitializer template< typename MeshConfig, typename Device, typename Mesh > class Initializer { using DeviceType = typename Mesh::DeviceType; using GlobalIndexType = typename Mesh::GlobalIndexType; using LocalIndexType = typename Mesh::LocalIndexType; using FaceType = typename Mesh::Face; using DeviceType = Device; using GlobalIndexType = typename MeshConfig::GlobalIndexType; using LocalIndexType = typename MeshConfig::LocalIndexType; protected: // _T is necessary to force *partial* specialization, since explicit specializations // at class scope are forbidden template< typename CurrentDimension = DimensionTag< Mesh::getMeshDimension() >, typename _T = void > template< typename CurrentDimension = DimensionTag< MeshConfig::meshDimension >, typename _T = void > struct BoundaryTagsNeedInitialization { using EntityTopology = typename MeshEntityTraits< typename Mesh::Config, DeviceType, CurrentDimension::value >::EntityTopology; static constexpr bool value = Mesh::Config::boundaryTagsStorage( EntityTopology() ) || using EntityTopology = typename MeshEntityTraits< MeshConfig, DeviceType, CurrentDimension::value >::EntityTopology; static constexpr bool value = MeshConfig::boundaryTagsStorage( EntityTopology() ) || BoundaryTagsNeedInitialization< typename CurrentDimension::Decrement >::value; }; template< typename _T > struct BoundaryTagsNeedInitialization< DimensionTag< 0 >, _T > { using EntityTopology = typename MeshEntityTraits< typename Mesh::Config, DeviceType, 0 >::EntityTopology; static constexpr bool value = Mesh::Config::boundaryTagsStorage( EntityTopology() ); using EntityTopology = typename MeshEntityTraits< MeshConfig, DeviceType, 0 >::EntityTopology; static constexpr bool value = MeshConfig::boundaryTagsStorage( EntityTopology() ); }; template< int Dimension > struct SetEntitiesCount { static void exec( Mesh& mesh ) { mesh.template boundaryTagsSetEntitiesCount< Dimension >( mesh.template getEntitiesCount< Dimension >() ); } }; template< int Dimension > Loading @@ -58,8 +66,8 @@ protected: template< int Subdimension > class InitializeSubentities { using SubentityTopology = typename MeshEntityTraits< typename Mesh::Config, DeviceType, Subdimension >::EntityTopology; static constexpr bool enabled = Mesh::Config::boundaryTagsStorage( SubentityTopology() ); using SubentityTopology = typename MeshEntityTraits< MeshConfig, DeviceType, Subdimension >::EntityTopology; static constexpr bool enabled = MeshConfig::boundaryTagsStorage( SubentityTopology() ); // _T is necessary to force *partial* specialization, since explicit specializations // at class scope are forbidden Loading @@ -67,7 +75,7 @@ protected: struct Worker { __cuda_callable__ static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const FaceType& face ) static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const typename Mesh::Face& face ) { const LocalIndexType subentitiesCount = face.template getSubentitiesCount< Subdimension >(); for( LocalIndexType i = 0; i < subentitiesCount; i++ ) { Loading @@ -81,12 +89,12 @@ protected: struct Worker< false, _T > { __cuda_callable__ static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const FaceType& face ) {} static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const typename Mesh::Face& face ) {} }; public: __cuda_callable__ static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const FaceType& face ) static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const typename Mesh::Face& face ) { Worker< enabled >::exec( mesh, faceIndex, face ); } Loading @@ -113,6 +121,7 @@ public: public: static void exec( Mesh& mesh ) { StaticFor< int, 0, Mesh::getMeshDimension() + 1, SetEntitiesCount >::execHost( mesh ); StaticFor< int, 0, Mesh::getMeshDimension() + 1, ResetBoundaryTags >::execHost( mesh ); auto kernel = [] __cuda_callable__ Loading Loading @@ -148,11 +157,12 @@ public: }; public: static void exec( Mesh& mesh ) void initLayer() { Worker<>::exec( mesh ); Worker<>::exec( *static_cast<Mesh*>(this) ); } }; } // namespace BoundaryTags } // namespace Meshes } // namespace TNL Loading
src/TNL/Meshes/Mesh.h +6 −11 Original line number Diff line number Diff line Loading @@ -20,15 +20,15 @@ #include <TNL/Object.h> #include <TNL/Logger.h> #include <TNL/Meshes/MeshEntity.h> #include <TNL/Meshes/MeshDetails/ConfigValidator.h> #include <TNL/Meshes/MeshDetails/traits/MeshTraits.h> #include <TNL/Meshes/MeshDetails/MeshLayers/StorageLayer.h> #include <TNL/Meshes/MeshDetails/ConfigValidator.h> #include <TNL/Meshes/MeshDetails/MeshLayers/BoundaryTags/LayerFamily.h> namespace TNL { namespace Meshes { template< typename MeshConfig > class Initializer; template< typename Mesh > class BoundaryTagsInitializer; template< typename Mesh > class EntityStorageRebinder; template< typename Mesh, int Dimension > struct IndexPermutationApplier; Loading Loading @@ -56,10 +56,12 @@ template< typename MeshConfig, class Mesh : public Object, public ConfigValidator< MeshConfig >, protected StorageLayerFamily< MeshConfig, Device >, public MeshInitializableBase< MeshConfig, Device, Mesh< MeshConfig, Device > > public MeshInitializableBase< MeshConfig, Device, Mesh< MeshConfig, Device > >, public StorageLayerFamily< MeshConfig, Device >, public BoundaryTags::LayerFamily< MeshConfig, Device, Mesh< MeshConfig, Device > > { using StorageBaseType = StorageLayerFamily< MeshConfig, Device >; using BoundaryTagsLayerFamily = BoundaryTags::LayerFamily< MeshConfig, Device, Mesh >; public: using Config = MeshConfig; Loading Loading @@ -110,11 +112,6 @@ class Mesh virtual String getSerializationTypeVirtual() const; using StorageBaseType::isBoundaryEntity; using StorageBaseType::getBoundaryEntitiesCount; using StorageBaseType::getBoundaryEntityIndex; using StorageBaseType::getInteriorEntitiesCount; using StorageBaseType::getInteriorEntityIndex; template< int Dimension > static constexpr bool entitiesAvailable(); Loading Loading @@ -180,8 +177,6 @@ class Mesh friend Initializer< MeshConfig >; friend BoundaryTagsInitializer< Mesh >; friend EntityStorageRebinder< Mesh >; template< typename Mesh, int Dimension > Loading
src/TNL/Meshes/MeshDetails/ConfigValidator.h +6 −30 Original line number Diff line number Diff line Loading @@ -71,28 +71,6 @@ class ConfigValidatorSupertopologyLayer< MeshConfig, EntityTopology, DimensionTa {}; template< typename MeshConfig, typename EntityTopology, bool BoundaryTagsStorage = MeshConfig::boundaryTagsStorage( EntityTopology() ) > class ConfigValidatorBoundaryTagsLayer { using FaceTopology = typename Topologies::Subtopology< typename MeshConfig::CellTopology, MeshConfig::meshDimension - 1 >::Topology; static_assert( MeshConfig::entityStorage( MeshConfig::meshDimension - 1 ), "Faces must be stored when any entity has boundary tags." ); static_assert( MeshConfig::superentityStorage( FaceTopology(), MeshConfig::meshDimension ), "Faces must store the cell superentity indices when any entity has boundary tags." ); static_assert( EntityTopology::dimension >= MeshConfig::meshDimension - 1 || MeshConfig::subentityStorage( FaceTopology(), EntityTopology::dimension ), "Faces must store the subentity indices of the entities on which the boundary tags are stored." ); }; template< typename MeshConfig, typename EntityTopology > class ConfigValidatorBoundaryTagsLayer< MeshConfig, EntityTopology, false > { }; template< typename MeshConfig, int dimension > class ConfigValidatorLayer : public ConfigValidatorLayer< MeshConfig, dimension - 1 >, Loading @@ -101,9 +79,7 @@ class ConfigValidatorLayer DimensionTag< dimension - 1 > >, public ConfigValidatorSupertopologyLayer< MeshConfig, typename Topologies::Subtopology< typename MeshConfig::CellTopology, dimension >::Topology, DimensionTag< MeshConfig::CellTopology::dimension > >, public ConfigValidatorBoundaryTagsLayer< MeshConfig, typename Topologies::Subtopology< typename MeshConfig::CellTopology, dimension >::Topology > DimensionTag< MeshConfig::CellTopology::dimension > > { using Topology = typename Topologies::Subtopology< typename MeshConfig::CellTopology, dimension >::Topology; Loading
src/TNL/Meshes/MeshDetails/MeshLayers/BoundaryTags/CMakeLists.txt 0 → 100644 +8 −0 Original line number Diff line number Diff line SET( headers ConfigValidator.h Layer.h LayerFamily.h Initializer.h Traits.h ) INSTALL( FILES ${headers} DESTINATION include/tnl-${tnlVersion}/TNL/Meshes/MeshDetails/MeshLayers/BoundaryTags )
src/TNL/Meshes/MeshDetails/MeshLayers/BoundaryTags/ConfigValidator.h 0 → 100644 +63 −0 Original line number Diff line number Diff line /*************************************************************************** ConfigValidator.h - description ------------------- begin : Aug 14, 2015 copyright : (C) 2015 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ #pragma once #include <TNL/Meshes/Topologies/SubentityVertexMap.h> #include <TNL/Meshes/MeshDetails/traits/MeshTraits.h> namespace TNL { namespace Meshes { namespace BoundaryTags { template< typename MeshConfig, typename EntityTopology, bool BoundaryTagsStorage = MeshConfig::boundaryTagsStorage( EntityTopology() ) > class ConfigValidatorBoundaryTagsLayer { using FaceTopology = typename Topologies::Subtopology< typename MeshConfig::CellTopology, MeshConfig::meshDimension - 1 >::Topology; static_assert( MeshConfig::entityStorage( MeshConfig::meshDimension - 1 ), "Faces must be stored when any entity has boundary tags." ); static_assert( MeshConfig::superentityStorage( FaceTopology(), MeshConfig::meshDimension ), "Faces must store the cell superentity indices when any entity has boundary tags." ); static_assert( EntityTopology::dimension >= MeshConfig::meshDimension - 1 || MeshConfig::subentityStorage( FaceTopology(), EntityTopology::dimension ), "Faces must store the subentity indices of the entities on which the boundary tags are stored." ); }; template< typename MeshConfig, typename EntityTopology > class ConfigValidatorBoundaryTagsLayer< MeshConfig, EntityTopology, false > { }; template< typename MeshConfig, int dimension = MeshConfig::meshDimension > class ConfigValidatorLayer : public ConfigValidatorLayer< MeshConfig, dimension - 1 >, public ConfigValidatorBoundaryTagsLayer< MeshConfig, typename MeshTraits< MeshConfig >::template EntityTraits< dimension >::EntityTopology > { }; template< typename MeshConfig > class ConfigValidatorLayer< MeshConfig, 0 > { }; template< typename MeshConfig > class ConfigValidator : public ConfigValidatorLayer< MeshConfig > { }; } // namespace BoundaryTags } // namespace Meshes } // namespace TNL
src/TNL/Meshes/MeshDetails/initializer/BoundaryTagsInitializer.h→src/TNL/Meshes/MeshDetails/MeshLayers/BoundaryTags/Initializer.h +30 −20 Original line number Diff line number Diff line /*************************************************************************** BoundaryTagsInitializer.h - description Initializer.h - description ------------------- begin : Dec 26, 2016 copyright : (C) 2016 by Tomas Oberhuber et al. Loading @@ -14,36 +14,44 @@ #include <TNL/ParallelFor.h> #include <TNL/DevicePointer.h> #include <TNL/Meshes/DimensionTag.h> #include <TNL/Meshes/MeshDetails/traits/MeshTraits.h> #include <TNL/Meshes/MeshDetails/traits/MeshEntityTraits.h> namespace TNL { namespace Meshes { namespace BoundaryTags { template< typename Mesh > class BoundaryTagsInitializer template< typename MeshConfig, typename Device, typename Mesh > class Initializer { using DeviceType = typename Mesh::DeviceType; using GlobalIndexType = typename Mesh::GlobalIndexType; using LocalIndexType = typename Mesh::LocalIndexType; using FaceType = typename Mesh::Face; using DeviceType = Device; using GlobalIndexType = typename MeshConfig::GlobalIndexType; using LocalIndexType = typename MeshConfig::LocalIndexType; protected: // _T is necessary to force *partial* specialization, since explicit specializations // at class scope are forbidden template< typename CurrentDimension = DimensionTag< Mesh::getMeshDimension() >, typename _T = void > template< typename CurrentDimension = DimensionTag< MeshConfig::meshDimension >, typename _T = void > struct BoundaryTagsNeedInitialization { using EntityTopology = typename MeshEntityTraits< typename Mesh::Config, DeviceType, CurrentDimension::value >::EntityTopology; static constexpr bool value = Mesh::Config::boundaryTagsStorage( EntityTopology() ) || using EntityTopology = typename MeshEntityTraits< MeshConfig, DeviceType, CurrentDimension::value >::EntityTopology; static constexpr bool value = MeshConfig::boundaryTagsStorage( EntityTopology() ) || BoundaryTagsNeedInitialization< typename CurrentDimension::Decrement >::value; }; template< typename _T > struct BoundaryTagsNeedInitialization< DimensionTag< 0 >, _T > { using EntityTopology = typename MeshEntityTraits< typename Mesh::Config, DeviceType, 0 >::EntityTopology; static constexpr bool value = Mesh::Config::boundaryTagsStorage( EntityTopology() ); using EntityTopology = typename MeshEntityTraits< MeshConfig, DeviceType, 0 >::EntityTopology; static constexpr bool value = MeshConfig::boundaryTagsStorage( EntityTopology() ); }; template< int Dimension > struct SetEntitiesCount { static void exec( Mesh& mesh ) { mesh.template boundaryTagsSetEntitiesCount< Dimension >( mesh.template getEntitiesCount< Dimension >() ); } }; template< int Dimension > Loading @@ -58,8 +66,8 @@ protected: template< int Subdimension > class InitializeSubentities { using SubentityTopology = typename MeshEntityTraits< typename Mesh::Config, DeviceType, Subdimension >::EntityTopology; static constexpr bool enabled = Mesh::Config::boundaryTagsStorage( SubentityTopology() ); using SubentityTopology = typename MeshEntityTraits< MeshConfig, DeviceType, Subdimension >::EntityTopology; static constexpr bool enabled = MeshConfig::boundaryTagsStorage( SubentityTopology() ); // _T is necessary to force *partial* specialization, since explicit specializations // at class scope are forbidden Loading @@ -67,7 +75,7 @@ protected: struct Worker { __cuda_callable__ static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const FaceType& face ) static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const typename Mesh::Face& face ) { const LocalIndexType subentitiesCount = face.template getSubentitiesCount< Subdimension >(); for( LocalIndexType i = 0; i < subentitiesCount; i++ ) { Loading @@ -81,12 +89,12 @@ protected: struct Worker< false, _T > { __cuda_callable__ static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const FaceType& face ) {} static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const typename Mesh::Face& face ) {} }; public: __cuda_callable__ static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const FaceType& face ) static void exec( Mesh& mesh, const GlobalIndexType& faceIndex, const typename Mesh::Face& face ) { Worker< enabled >::exec( mesh, faceIndex, face ); } Loading @@ -113,6 +121,7 @@ public: public: static void exec( Mesh& mesh ) { StaticFor< int, 0, Mesh::getMeshDimension() + 1, SetEntitiesCount >::execHost( mesh ); StaticFor< int, 0, Mesh::getMeshDimension() + 1, ResetBoundaryTags >::execHost( mesh ); auto kernel = [] __cuda_callable__ Loading Loading @@ -148,11 +157,12 @@ public: }; public: static void exec( Mesh& mesh ) void initLayer() { Worker<>::exec( mesh ); Worker<>::exec( *static_cast<Mesh*>(this) ); } }; } // namespace BoundaryTags } // namespace Meshes } // namespace TNL