Skip to content
Snippets Groups Projects
HeatEquationBenchmarkProblem_impl.h 25.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifndef HeatEquationBenchmarkPROBLEM_IMPL_H_
    #define HeatEquationBenchmarkPROBLEM_IMPL_H_
    
    #include <core/mfilename.h>
    #include <matrices/tnlMatrixSetter.h>
    #include <solvers/pde/tnlExplicitUpdater.h>
    #include <solvers/pde/tnlLinearSystemAssembler.h>
    #include <solvers/pde/tnlBackwardTimeDiscretisation.h>
    
    #include "TestGridEntity.h"
    
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    tnlString
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    getTypeStatic()
    {
       return tnlString( "HeatEquationBenchmarkProblem< " ) + Mesh :: getTypeStatic() + " >";
    }
    
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    HeatEquationBenchmarkProblem()
    : cudaMesh( 0 ),
      cudaBoundaryConditions( 0 ),
      cudaRightHandSide( 0 ),
      cudaDifferentialOperator( 0 )
    {
    }
    
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    tnlString
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    getPrologHeader() const
    {
       return tnlString( "Heat Equation Benchmark" );
    }
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    void
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    writeProlog( tnlLogger& logger, const tnlParameterContainer& parameters ) const
    {
       /****
        * Add data you want to have in the computation report (log) as follows:
        * logger.writeParameter< double >( "Parameter description", parameter );
        */
    }
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    bool
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    setup( const tnlParameterContainer& parameters )
    {
    
       if( ! this->boundaryConditionPointer->setup( parameters, "boundary-conditions-" ) ||
           ! this->rightHandSidePointer->setup( parameters, "right-hand-side-" ) )
    
       this->cudaKernelType = parameters.getParameter< tnlString >( "cuda-kernel-type" );
    
       if( std::is_same< DeviceType, tnlCuda >::value )
       {
    
          this->cudaBoundaryConditions = tnlCuda::passToDevice( *this->boundaryConditionPointer );
          this->cudaRightHandSide = tnlCuda::passToDevice( *this->rightHandSidePointer );
          this->cudaDifferentialOperator = tnlCuda::passToDevice( *this->differentialOperatorPointer );
    
       return true;
    }
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    typename HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::IndexType
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    
    Tomáš Oberhuber's avatar
    Tomáš Oberhuber committed
    getDofs( const MeshPointer& meshPointer ) const
    
    {
       /****
        * Return number of  DOFs (degrees of freedom) i.e. number
        * of unknowns to be resolved by the main solver.
        */
    
    Tomáš Oberhuber's avatar
    Tomáš Oberhuber committed
       return meshPointer->template getEntitiesCount< typename MeshType::Cell >();
    
    }
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    void
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    
    bindDofs( const MeshPointer& meshPointer,
    
              DofVectorPointer& dofsPointer )
    
    {
    }
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    bool
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    setInitialCondition( const tnlParameterContainer& parameters,
    
                         const MeshPointer& meshPointer,
    
                         DofVectorPointer& dofsPointer,
    
                         MeshDependentDataType& meshDependentData )
    {
       const tnlString& initialConditionFile = parameters.getParameter< tnlString >( "initial-condition" );
    
       tnlMeshFunction< Mesh > u( meshPointer, dofsPointer );
    
       if( ! u.boundLoad( initialConditionFile ) )
       {
          cerr << "I am not able to load the initial condition from the file " << initialConditionFile << "." << endl;
          return false;
       }
       return true; 
    }
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
       template< typename Matrix >
    bool
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    setupLinearSystem( const MeshType& mesh,
                       Matrix& matrix )
    {
       const IndexType dofs = this->getDofs( mesh );
       typedef typename Matrix::CompressedRowsLengthsVector CompressedRowsLengthsVectorType;
       CompressedRowsLengthsVectorType rowLengths;
       if( ! rowLengths.setSize( dofs ) )
          return false;
       tnlMatrixSetter< MeshType, DifferentialOperator, BoundaryCondition, CompressedRowsLengthsVectorType > matrixSetter;
       matrixSetter.template getCompressedRowsLengths< typename Mesh::Cell >( mesh,
    
                                                                              differentialOperatorPointer,
                                                                              boundaryConditionPointer,
    
                                                                              rowLengths );
       matrix.setDimensions( dofs, dofs );
       if( ! matrix.setCompressedRowsLengths( rowLengths ) )
          return false;
       return true;
    }
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    bool
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    makeSnapshot( const RealType& time,
                  const IndexType& step,
    
                  const MeshPointer& meshPointer,
    
                  DofVectorPointer& dofsPointer,
    
                  MeshDependentDataType& meshDependentData )
    {
       cout << endl << "Writing output at time " << time << " step " << step << "." << endl;
    
       this->bindDofs( meshPointer, dofsPointer );
    
       MeshFunctionType u;
    
       u.bind( meshPointer, *dofsPointer );
    
       tnlString fileName;
       FileNameBaseNumberEnding( "u-", step, 5, ".tnl", fileName );
    
       if( ! u.save( fileName ) )
    
    #ifdef HAVE_CUDA
    
    template< typename Real, typename Index >
    __global__ void boundaryConditionsKernel( Real* u,
                                              Real* fu,
                                              const Index gridXSize, const Index gridYSize )
    {
       const Index i = ( blockIdx.x ) * blockDim.x + threadIdx.x;
       const Index j = ( blockIdx.y ) * blockDim.y + threadIdx.y;
       if( i == 0 && j < gridYSize )
       {
          fu[ j * gridXSize ] = 0.0;
          u[ j * gridXSize ] = 0.0; //u[ j * gridXSize + 1 ];
       }
       if( i == gridXSize - 1 && j < gridYSize )
       {
          fu[ j * gridXSize + gridYSize - 1 ] = 0.0;
          u[ j * gridXSize + gridYSize - 1 ] = 0.0; //u[ j * gridXSize + gridXSize - 1 ];      
       }
       if( j == 0 && i > 0 && i < gridXSize - 1 )
       {
          fu[ i ] = 0.0; //u[ j * gridXSize + 1 ];
          u[ i ] = 0.0; //u[ j * gridXSize + 1 ];
       }
       if( j == gridYSize -1  && i > 0 && i < gridXSize - 1 )
       {
          fu[ j * gridXSize + i ] = 0.0; //u[ j * gridXSize + gridXSize - 1 ];      
          u[ j * gridXSize + i ] = 0.0; //u[ j * gridXSize + gridXSize - 1 ];      
       }         
    }
    
    
    template< typename Real, typename Index >
    __global__ void heatEquationKernel( const Real* u, 
                                        Real* fu,
                                        const Real tau,
                                        const Real hx_inv,
                                        const Real hy_inv,
                                        const Index gridXSize,
                                        const Index gridYSize )
    {
       const Index i = blockIdx.x * blockDim.x + threadIdx.x;
       const Index j = blockIdx.y * blockDim.y + threadIdx.y;
       if( i > 0 && i < gridXSize - 1 &&
           j > 0 && j < gridYSize - 1 )
       {
          const Index c = j * gridXSize + i;
          fu[ c ] = ( u[ c - 1 ] - 2.0 * u[ c ] + u[ c + 1 ] ) * hx_inv +
                    ( u[ c - gridXSize ] - 2.0 * u[ c ] + u[ c + gridXSize ] ) * hy_inv;
       }
    }
    
    
    template< typename GridType,
              typename GridEntity,
              typename BoundaryConditions,
              typename MeshFunction >
    __global__ void 
    
    boundaryConditionsTemplatedCompact( const GridType* grid,
                                        const BoundaryConditions* boundaryConditions,
                                        MeshFunction* u,
    
                                        const typename GridType::RealType time,
                                        const typename GridEntity::CoordinatesType begin,
                                        const typename GridEntity::CoordinatesType end,
                                        const typename GridEntity::EntityOrientationType entityOrientation,
                                        const typename GridEntity::EntityBasisType entityBasis,   
                                        const typename GridType::IndexType gridXIdx,
                                        const typename GridType::IndexType gridYIdx )
    {
    
       /*typename GridType::CoordinatesType coordinates;
    
    
       coordinates.x() = begin.x() + ( gridXIdx * tnlCuda::getMaxGridSize() + blockIdx.x ) * blockDim.x + threadIdx.x;
       coordinates.y() = begin.y() + ( gridYIdx * tnlCuda::getMaxGridSize() + blockIdx.y ) * blockDim.y + threadIdx.y;  
       
    
       GridEntity entity( *grid, coordinates, entityOrientation, entityBasis );
    
    
       if( entity.getCoordinates().x() < end.x() &&
           entity.getCoordinates().y() < end.y() )
       {
          entity.refresh();
          if( entity.isBoundaryEntity() )
          {
    
             ( *u )( entity ) = ( *boundaryConditions )( *u, entity, time );
    
       }*/
       
       typedef typename GridEntity::IndexType IndexType;
    
       typedef typename GridEntity::RealType RealType;
    
       RealType* _u = &( *u )[ 0 ];
    
       const IndexType tidX = begin.x() + ( gridXIdx * tnlCuda::getMaxGridSize() + blockIdx.x ) * blockDim.x + threadIdx.x;
       const IndexType tidY = begin.y() + ( gridYIdx * tnlCuda::getMaxGridSize() + blockIdx.y ) * blockDim.y + threadIdx.y;
       if( tidX == 0 || tidX == end.x() - 1 || tidY == 0 || tidY == end.y() - 1 )      
       {
    
          _u[ tidY * grid->getDimensions().x() + tidX ] = 0.0;
    
    template< typename EntityType, int Dimensions >
    struct EntityPointer : public EntityPointer< EntityType, Dimensions - 1 >
    {
       __device__ EntityPointer( const EntityType* ptr )
          : EntityPointer< EntityType, Dimensions - 1 >( ptr ), pointer( ptr )
       {      
       }
       
       const EntityType* pointer;
    };
    
    template< typename EntityType >
    struct EntityPointer< EntityType, 0 >
    {
       __device__ inline EntityPointer( const EntityType* ptr )
       :pointer( ptr )
       {      
       }
    
       
       const EntityType* pointer;
    };
    
    template< typename GridType >
    struct TestEntity
    {
       typedef typename GridType::Cell::CoordinatesType CoordinatesType;
       
       __device__ inline TestEntity( const GridType& grid,
                   const typename GridType::Cell::CoordinatesType& coordinates,
                   const typename GridType::Cell::EntityOrientationType& orientation,
                   const typename GridType::Cell::EntityBasisType& basis )
       : grid( grid ),
          coordinates( coordinates ),
          orientation( orientation ),
          basis( basis ),
          entityIndex( 0 ),
          ptr( &grid )
       {      
       };
      
       const GridType& grid;
       
       EntityPointer< GridType, 2 > ptr; 
       //TestEntity< GridType > *entity1, *entity2, *entity3;
       
       typename GridType::IndexType entityIndex;      
       
       const typename GridType::Cell::CoordinatesType coordinates;
       const typename GridType::Cell::EntityOrientationType orientation;
       const typename GridType::Cell::EntityBasisType basis;
       
    };
    
    
    template< typename GridType,
              typename GridEntity,
              typename DifferentialOperator,
              typename RightHandSide,
              typename MeshFunction >
    __global__ void 
    
    heatEquationTemplatedCompact( const GridType* grid,
                                  const DifferentialOperator* differentialOperator,
                                  const RightHandSide* rightHandSide,
    
                                  MeshFunction* _u,
                                  MeshFunction* _fu,
    
                                  const typename GridType::RealType time,
                                  const typename GridEntity::CoordinatesType begin,
                                  const typename GridEntity::CoordinatesType end,
                                  const typename GridEntity::EntityOrientationType entityOrientation,
                                  const typename GridEntity::EntityBasisType entityBasis,   
                                  const typename GridType::IndexType gridXIdx,
                                  const typename GridType::IndexType gridYIdx )
    {
       typename GridType::CoordinatesType coordinates;
       typedef typename GridType::IndexType IndexType;
       typedef typename GridType::RealType RealType;
    
    
       //TestEntity< GridType > *entities = getSharedMemory< TestEntity< GridType > >();
       //TestEntity< GridType >& entity = entities[ threadIdx.y * 16 + threadIdx.x ];
       //new ( &entity ) TestEntity< GridType >( *grid, coordinates, entityOrientation, entityBasis );
    
       coordinates.x() = begin.x() + ( gridXIdx * tnlCuda::getMaxGridSize() + blockIdx.x ) * blockDim.x + threadIdx.x;
    
       coordinates.y() = begin.y() + ( gridYIdx * tnlCuda::getMaxGridSize() + blockIdx.y ) * blockDim.y + threadIdx.y;  
       
    
       //TestEntity< GridType > entity( *grid, coordinates, entityOrientation, entityBasis );
       GridEntity entity( *grid, coordinates, entityOrientation, entityBasis );
    
       //const GridType* g = grid;
    
       //MeshFunction& u = *_u;
       //MeshFunction& fu = *_fu;
    
       //if( threadIdx.x == 0 )
       //   printf( "entity size = %d \n", sizeof( GridEntity ) );
    
       //if( entity.getCoordinates().x() < end.x() &&
       //    entity.getCoordinates().y() < end.y() )
    
          //entity.refresh();
    
          /*if( ! entity.isBoundaryEntity() )
    
                ( *differentialOperator )( u, entity, time );
    
             typedef tnlFunctionAdapter< GridType, RightHandSide > FunctionAdapter;
    
             fu( entity ) +=  FunctionAdapter::getValue( *rightHandSide, entity, time );
    
       //GridEntity entity( grid, coordinates, entityOrientation, entityBasis );
       //printf( "size = %d ", sizeof( GridEntity ) );
    
       //entity.refresh();
    
       //typename GridType::TestCell entity( grid, coordinates, entityOrientation, entityBasis );
    
       const IndexType tidX = begin.x() + ( gridXIdx * tnlCuda::getMaxGridSize() + blockIdx.x ) * blockDim.x + threadIdx.x;
    
       const IndexType tidY = begin.y() + ( gridYIdx * tnlCuda::getMaxGridSize() + blockIdx.y ) * blockDim.y + threadIdx.y;
    
       MeshFunction& u = *_u;
       MeshFunction& fu = *_fu;
    
       if( tidX > 0 && tidX < end.x() - 1 && tidY > 0 && tidY < end.y() - 1 )      
       {
    
          const IndexType& xSize = grid->getDimensions().x();
    
          const IndexType& c = tidY * xSize + tidX;
    
          const RealType& hxSquareInverse = grid->template getSpaceStepsProducts< -2, 0 >(); 
          const RealType& hySquareInverse = grid->template getSpaceStepsProducts< 0, -2 >(); 
    
          fu[ c ] = ( u[ c - 1 ] - 2.0 * u[ c ] + u[ c + 1 ]  ) * hxSquareInverse +
                    ( u[ c - xSize ] - 2.0 * u[ c ] + u[ c + xSize ] ) * hySquareInverse;      
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    void
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    getExplicitRHS( const RealType& time,
                    const RealType& tau,
    
                    const MeshPointer& mesh,
                    DofVectorPointer& uDofs,
                    DofVectorPointer& fuDofs,
    
                    MeshDependentDataType& meshDependentData )
    {
       /****
        * If you use an explicit solver like tnlEulerSolver or tnlMersonSolver, you
        * need to implement this method. Compute the right-hand side of
        *
        *   d/dt u(x) = fu( x, u )
        *
        * You may use supporting mesh dependent data if you need.
        */
    
    
       if( std::is_same< DeviceType, tnlHost >::value )
    
          const IndexType gridXSize = mesh->getDimensions().x();
          const IndexType gridYSize = mesh->getDimensions().y();
          const RealType& hx_inv = mesh->template getSpaceStepsProducts< -2,  0 >();
          const RealType& hy_inv = mesh->template getSpaceStepsProducts<  0, -2 >();
          RealType* u = uDofs->getData();
          RealType* fu = fuDofs->getData();
    
          for( IndexType j = 0; j < gridYSize; j++ )
    
             fu[ j * gridXSize ] = 0.0; //u[ j * gridXSize + 1 ];
             fu[ j * gridXSize + gridXSize - 2 ] = 0.0; //u[ j * gridXSize + gridXSize - 1 ];
    
          for( IndexType i = 0; i < gridXSize; i++ )
          {
             fu[ i ] = 0.0; //u[ gridXSize + i ];
             fu[ ( gridYSize - 1 ) * gridXSize + i ] = 0.0; //u[ ( gridYSize - 2 ) * gridXSize + i ];
          }
    
          
          /*typedef typename MeshType::Cell CellType;
          typedef typename CellType::CoordinatesType CoordinatesType;
          CoordinatesType coordinates( 0, 0 ), entityOrientation( 0,0 ), entityBasis( 0, 0 );*/
          
          //CellType entity( mesh, coordinates, entityOrientation, entityBasis );
    
    
          for( IndexType j = 1; j < gridYSize - 1; j++ )
             for( IndexType i = 1; i < gridXSize - 1; i++ )
             {
                const IndexType c = j * gridXSize + i;
                fu[ c ] = tau * ( ( u[ c - 1 ] - 2.0 * u[ c ] + u[ c + 1 ] ) * hx_inv +
                                  ( u[ c - gridXSize ] - 2.0 * u[ c ] + u[ c + gridXSize ] ) * hy_inv );
             }
       }
    
       if( std::is_same< DeviceType, tnlCuda >::value )
       {
    
          #ifdef HAVE_CUDA         
    
          if( this->cudaKernelType == "pure-c" )
    
             const IndexType gridXSize = mesh->getDimensions().x();
             const IndexType gridYSize = mesh->getDimensions().y();
             const RealType& hx_inv = mesh->template getSpaceStepsProducts< -2,  0 >();
             const RealType& hy_inv = mesh->template getSpaceStepsProducts<  0, -2 >();
    
    
             dim3 cudaBlockSize( 16, 16 );
             dim3 cudaGridSize( gridXSize / 16 + ( gridXSize % 16 != 0 ),
                                gridYSize / 16 + ( gridYSize % 16 != 0 ) );
    
             boundaryConditionsKernel<<< cudaGridSize, cudaBlockSize >>>( uDofs->getData(), fuDofs->getData(), gridXSize, gridYSize );
    
             if( ( cudaErr = cudaGetLastError() ) != cudaSuccess )
             {
                cerr << "Setting of boundary conditions failed. " << cudaErr << endl;
                return;
             }
    
             /****
              * Laplace operator
              */
             //cout << "Laplace operator ... " << endl;
             heatEquationKernel<<< cudaGridSize, cudaBlockSize >>>
    
                ( uDofs->getData(), fuDofs->getData(), tau, hx_inv, hy_inv, gridXSize, gridYSize );
    
             if( cudaGetLastError() != cudaSuccess )
             {
                cerr << "Laplace operator failed." << endl;
                return;
             }
          }
          if( this->cudaKernelType == "templated-compact" )
    
             typedef typename MeshType::MeshEntity< 2 > CellType;
             //typedef typename MeshType::Cell CellType;
    
             //std::cerr << "Size of entity is ... " << sizeof( TestEntity< MeshType > ) << " vs. " << sizeof( CellType ) << std::endl;
    
             typedef typename CellType::CoordinatesType CoordinatesType;
    
             u->bind( mesh, uDofs );
             fu->bind( mesh, fuDofs );
             fu->getData().setValue( 1.0 );
    
             const CoordinatesType begin( 0,0 );
    
             const CoordinatesType& end = mesh->getDimensions();
             CellType cell( mesh.template getData< DeviceType >() );
    
             dim3 cudaBlockSize( 16, 16 );
             dim3 cudaBlocks;
             cudaBlocks.x = tnlCuda::getNumberOfBlocks( end.x() - begin.x() + 1, cudaBlockSize.x );
             cudaBlocks.y = tnlCuda::getNumberOfBlocks( end.y() - begin.y() + 1, cudaBlockSize.y );
             const IndexType cudaXGrids = tnlCuda::getNumberOfGrids( cudaBlocks.x );
             const IndexType cudaYGrids = tnlCuda::getNumberOfGrids( cudaBlocks.y );
             
             //std::cerr << "Setting boundary conditions..." << std::endl;
    
    
             tnlCuda::synchronizeDevice();
    
             for( IndexType gridYIdx = 0; gridYIdx < cudaYGrids; gridYIdx ++ )
                for( IndexType gridXIdx = 0; gridXIdx < cudaXGrids; gridXIdx ++ )
                   boundaryConditionsTemplatedCompact< MeshType, CellType, BoundaryCondition, MeshFunctionType >
                      <<< cudaBlocks, cudaBlockSize >>>
    
                      ( &mesh.template getData< tnlCuda >(),
                        &boundaryConditionPointer.template getData< tnlCuda >(),
    
                        &u.template modifyData< tnlCuda >(),
    
                        time,
                        begin,
                        end,
                        cell.getOrientation(),
                        cell.getBasis(),
                        gridXIdx,
                        gridYIdx );
             cudaThreadSynchronize();
             
             //std::cerr << "Computing the heat equation ..." << std::endl;
             for( IndexType gridYIdx = 0; gridYIdx < cudaYGrids; gridYIdx ++ )
                for( IndexType gridXIdx = 0; gridXIdx < cudaXGrids; gridXIdx ++ )
                   heatEquationTemplatedCompact< MeshType, CellType, DifferentialOperator, RightHandSide, MeshFunctionType >
                      <<< cudaBlocks, cudaBlockSize >>>
    
                      ( &mesh.template getData< DeviceType >(),
                        &differentialOperatorPointer.template getData< DeviceType >(),
                        &rightHandSidePointer.template getData< DeviceType >(),
    
                        &u.template modifyData< DeviceType >(),
                        &fu.template modifyData< DeviceType >(),
    
                        time,
                        begin,
                        end,
                        cell.getOrientation(),
                        cell.getBasis(),
                        gridXIdx,
                        gridYIdx );
             checkCudaDevice;
             cudaThreadSynchronize();         
    
          #endif
          if( this->cudaKernelType == "templated" )
          {
             //if( !this->cudaMesh )
             //   this->cudaMesh = tnlCuda::passToDevice( &mesh );
    
             MeshFunctionPointer uPointer( mesh, uDofs );
             MeshFunctionPointer fuPointer( mesh, fuDofs );
    
             tnlExplicitUpdater< Mesh, MeshFunctionType, DifferentialOperator, BoundaryCondition, RightHandSide > explicitUpdater;
             //explicitUpdater.setGPUTransferTimer( this->gpuTransferTimer ); 
    
             explicitUpdater.template update< typename Mesh::Cell >( 
    
                this->differentialOperatorPointer,
                this->boundaryConditionPointer,
                this->rightHandSidePointer,
    
                uPointer,
                fuPointer );
    
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    
       template< typename MatrixPointer >
    
    void
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    assemblyLinearSystem( const RealType& time,
                          const RealType& tau,
    
                          const MeshPointer& mesh,
                          DofVectorPointer& _u,
                          MatrixPointer& matrix,
                          DofVectorPointer& b,
    
                          MeshDependentDataType& meshDependentData )
    {
       tnlLinearSystemAssembler< Mesh,
                                 MeshFunctionType,
                                 DifferentialOperator,
                                 BoundaryCondition,
                                 RightHandSide,
                                 tnlBackwardTimeDiscretisation,
    
                                 typename MatrixPointer::ObjectType,
                                 typename DofVectorPointer::ObjectType > systemAssembler;
    
       typedef tnlMeshFunction< Mesh > MeshFunctionType;
       typedef tnlSharedPointer< MeshFunctionType, DeviceType > MeshFunctionPointer;
       MeshFunctionPointer u( mesh, *_u );
    
       systemAssembler.template assembly< typename Mesh::Cell >( time,
                                                                 tau,
                                                                 mesh,
                                                                 this->differentialOperator,
                                                                 this->boundaryCondition,
                                                                 this->rightHandSide,
                                                                 u,
                                                                 matrix,
                                                                 b );
    }
    
    
    template< typename Mesh,
              typename BoundaryCondition,
              typename RightHandSide,
              typename DifferentialOperator >
    HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
    ~HeatEquationBenchmarkProblem()
    {
       if( this->cudaMesh ) tnlCuda::freeFromDevice( this->cudaMesh );
       if( this->cudaBoundaryConditions )  tnlCuda::freeFromDevice( this->cudaBoundaryConditions );
       if( this->cudaRightHandSide ) tnlCuda::freeFromDevice( this->cudaRightHandSide );
       if( this->cudaDifferentialOperator ) tnlCuda::freeFromDevice( this->cudaDifferentialOperator );
    }
    
    
    
    #endif /* HeatEquationBenchmarkPROBLEM_IMPL_H_ */