Newer
Older
#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>
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 >::
{
/****
* Return number of DOFs (degrees of freedom) i.e. number
* of unknowns to be resolved by the main solver.
*/
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,
{
}
template< typename Mesh,
typename BoundaryCondition,
typename RightHandSide,
typename DifferentialOperator >
bool
HeatEquationBenchmarkProblem< Mesh, BoundaryCondition, RightHandSide, DifferentialOperator >::
setInitialCondition( const tnlParameterContainer& parameters,
const MeshPointer& meshPointer,
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,
MeshDependentDataType& meshDependentData )
{
cout << endl << "Writing output at time " << time << " step " << step << "." << endl;
this->bindDofs( meshPointer, dofsPointer );
u.bind( meshPointer, *dofsPointer );
tnlString fileName;
FileNameBaseNumberEnding( "u-", step, 5, ".tnl", fileName );
return false;
return true;
}
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#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;
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;
}
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
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 );
//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() )
{
( *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 ) );
//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 )
{
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 ) );
int cudaErr;
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;
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 >(
time,
this->differentialOperatorPointer,
this->boundaryConditionPointer,
this->rightHandSidePointer,
template< typename Mesh,
typename BoundaryCondition,
typename RightHandSide,
typename DifferentialOperator >
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_ */