Newer
Older

Vít Hanousek
committed
/***************************************************************************
DistributedGridTest.cpp - description
-------------------
begin : Sep 6, 2017
copyright : (C) 2017 by Tomas Oberhuber et al.
email : tomas.oberhuber@fjfi.cvut.cz
***************************************************************************/
#ifdef HAVE_GTEST
#include <gtest/gtest.h>

Vít Hanousek
committed
#ifdef HAVE_MPI

Vít Hanousek
committed
#include <TNL/Communicators/MpiCommunicator.h>
#include <TNL/Communicators/ScopedInitializer.h>

Vít Hanousek
committed
#include <TNL/Functions/MeshFunction.h>
Tomáš Oberhuber
committed
#include <TNL/Meshes/DistributedMeshes/DistributedMesh.h>
#include <TNL/Meshes/DistributedMeshes/SubdomainOverlapsGetter.h>

Vít Hanousek
committed
Tomáš Oberhuber
committed
#include "../../Functions/Functions.h"

Vít Hanousek
committed
using namespace TNL;
using namespace TNL::Containers;
using namespace TNL::Meshes;
using namespace TNL::Meshes::DistributedMeshes;

Vít Hanousek
committed
using namespace TNL::Functions;
using namespace TNL::Devices;
using namespace TNL::Communicators;

Vít Hanousek
committed
template<typename DofType>
void setDof_1D( DofType &dof, typename DofType::RealType value )

Vít Hanousek
committed
{
for( int i = 0; i < dof.getSize(); i++ )
dof[ i ] = value;

Vít Hanousek
committed
}
template<typename DofType>
void check_Boundary_1D(int rank, int nproc, const DofType& dof, typename DofType::RealType expectedValue)

Vít Hanousek
committed
{

Vít Hanousek
committed
if(rank==0)//Left
{
EXPECT_EQ( dof[0], expectedValue) << "Left boundary test failed";
return;
}
if(rank==(nproc-1))//Right
{
EXPECT_EQ( dof[dof.getSize()-1], expectedValue) << "Right boundary test failed";
return;
}

Vít Hanousek
committed
};
template<typename DofType>
void check_Overlap_1D(int rank, int nproc, const DofType& dof, typename DofType::RealType expectedValue)

Vít Hanousek
committed
{

Vít Hanousek
committed
{
EXPECT_EQ( dof[dof.getSize()-1], expectedValue) << "Left boundary node overlap test failed";
return;
}
if( rank == ( nproc - 1 ) )

Vít Hanousek
committed
{
EXPECT_EQ( dof[0], expectedValue) << "Right boundary node overlap test failed";
return;
}
EXPECT_EQ( dof[0], expectedValue) << "left overlap test failed";
EXPECT_EQ( dof[dof.getSize()-1], expectedValue)<< "right overlap test failed";

Vít Hanousek
committed
};
template<typename DofType>
void check_Inner_1D(int rank, int nproc, const DofType& dof, typename DofType::RealType expectedValue)

Vít Hanousek
committed
{
for( int i = 1; i < ( dof.getSize()-2 ); i++ )
EXPECT_EQ( dof[i], expectedValue) << " " << i;

Vít Hanousek
committed
};
/*
Tomáš Oberhuber
committed
* Light check of 1D distributed grid and its synchronization.
* Number of process is not limited.
* Overlap is limited to 1

Vít Hanousek
committed
* Only double is tested as dof Real type -- it may be changed, extend test
* Global size is hardcoded as 10 -- it can be changed, extend test
*/
typedef MpiCommunicator CommunicatorType;
Tomáš Oberhuber
committed
typedef Grid<1,double,Host,int> GridType;
typedef MeshFunction< GridType > MeshFunctionType;
typedef MeshFunction< GridType, GridType::getMeshDimension(), bool > MaskType;
typedef Vector< double,Host,int> DofType;
typedef Vector< bool, Host, int > MaskDofType;
Tomáš Oberhuber
committed
typedef typename GridType::Cell Cell;
typedef typename GridType::IndexType IndexType;
typedef typename GridType::PointType PointType;
typedef DistributedMesh<GridType> DistributedGridType;

Vít Hanousek
committed
class DistributedGridTest_1D : public ::testing::Test
Tomáš Oberhuber
committed
{
protected:

Vít Hanousek
committed
DistributedMesh< GridType > *distributedGrid;
MaskDofType maskDofs;

Vít Hanousek
committed
Pointers::SharedPointer< GridType > gridptr;
Pointers::SharedPointer< MeshFunctionType > meshFunctionPtr;
Pointers::SharedPointer< MaskType > maskPointer;

Vít Hanousek
committed
MeshFunctionEvaluator< MeshFunctionType, ConstFunction< double, 1 > > constFunctionEvaluator;
Pointers::SharedPointer< ConstFunction< double, 1 >, Host > constFunctionPtr;

Vít Hanousek
committed
MeshFunctionEvaluator< MeshFunctionType, LinearFunction< double, 1 > > linearFunctionEvaluator;
Pointers::SharedPointer< LinearFunction< double, 1 >, Host > linearFunctionPtr;

Vít Hanousek
committed
int rank;
int nproc;

Vít Hanousek
committed
void SetUp()
Tomáš Oberhuber
committed
{
int size=10;
rank=CommunicatorType::GetRank(CommunicatorType::AllGroup);
nproc=CommunicatorType::GetSize(CommunicatorType::AllGroup);
PointType globalOrigin;
PointType globalProportions;
GridType globalGrid;
globalOrigin.x()=-0.5;
globalProportions.x()=size;
globalGrid.setDimensions(size);
globalGrid.setDomain(globalOrigin,globalProportions);
typename DistributedGridType::CoordinatesType overlap;
overlap.setValue(1);
distributedGrid=new DistributedGridType();
Tomáš Oberhuber
committed
typename DistributedGridType::SubdomainOverlapsType lowerOverlap, upperOverlap;
distributedGrid->template setGlobalGrid<CommunicatorType>( globalGrid );
//distributedGrid->setupGrid(*gridptr);
SubdomainOverlapsGetter< GridType, CommunicatorType >::
getOverlaps( distributedGrid, lowerOverlap, upperOverlap, 1 );
distributedGrid->setOverlaps( lowerOverlap, upperOverlap );
Tomáš Oberhuber
committed
distributedGrid->setupGrid(*gridptr);
dof.setSize( gridptr->template getEntitiesCount< Cell >() );
Tomáš Oberhuber
committed
meshFunctionPtr->bind(gridptr,dof);
Tomáš Oberhuber
committed
constFunctionPtr->Number=rank;
}
void SetUpPeriodicBoundaries()
{
typename DistributedGridType::SubdomainOverlapsType lowerOverlap, upperOverlap;
SubdomainOverlapsGetter< GridType, CommunicatorType >::
getOverlaps( distributedGrid, lowerOverlap, upperOverlap, 1 );
distributedGrid->setOverlaps( lowerOverlap, upperOverlap );
distributedGrid->setupGrid(*gridptr);
}

Vít Hanousek
committed
void TearDown()
{
delete distributedGrid;
}

Vít Hanousek
committed
};
TEST_F( DistributedGridTest_1D, isBoundaryDomainTest )
{
if( rank == 0 || rank == nproc - 1 )
EXPECT_TRUE( distributedGrid->isBoundarySubdomain() );
else
EXPECT_FALSE( distributedGrid->isBoundarySubdomain() );
}
TEST_F(DistributedGridTest_1D, evaluateAllEntities)

Vít Hanousek
committed
{
//Check Traversars
//All entities, witout overlap
setDof_1D( dof,-1);
constFunctionEvaluator.evaluateAllEntities( meshFunctionPtr , constFunctionPtr );
//Printer<GridType,DofType>::print_dof(rank,*gridptr,dof);
check_Boundary_1D(rank, nproc, dof, rank);
check_Overlap_1D(rank, nproc, dof, -1);
check_Inner_1D(rank, nproc, dof, rank);

Vít Hanousek
committed
}
TEST_F(DistributedGridTest_1D, evaluateBoundaryEntities)

Vít Hanousek
committed
{
//Boundary entities, witout overlap
setDof_1D(dof,-1);
constFunctionEvaluator.evaluateBoundaryEntities( meshFunctionPtr , constFunctionPtr );
check_Boundary_1D(rank, nproc, dof, rank);
check_Overlap_1D(rank, nproc, dof, -1);
check_Inner_1D(rank, nproc, dof, -1);

Vít Hanousek
committed
}
TEST_F(DistributedGridTest_1D, evaluateInteriorEntities)

Vít Hanousek
committed
{
//Inner entities, witout overlap
setDof_1D(dof,-1);
constFunctionEvaluator.evaluateInteriorEntities( meshFunctionPtr , constFunctionPtr );
check_Boundary_1D(rank, nproc, dof, -1);
check_Overlap_1D(rank, nproc, dof, -1);
check_Inner_1D(rank, nproc, dof, rank);

Vít Hanousek
committed
}
TEST_F(DistributedGridTest_1D, SynchronizerNeighborsTest )

Vít Hanousek
committed
{
setDof_1D(dof,-1);
constFunctionEvaluator.evaluateAllEntities( meshFunctionPtr , constFunctionPtr );
meshFunctionPtr->template synchronize<CommunicatorType>();
if(rank!=0)
EXPECT_EQ((dof)[0],rank-1)<< "Left Overlap was filled by wrong process.";
if(rank!=nproc-1)
EXPECT_EQ((dof)[dof.getSize()-1],rank+1)<< "Right Overlap was filled by wrong process.";

Vít Hanousek
committed
}
Tomáš Oberhuber
committed
TEST_F(DistributedGridTest_1D, EvaluateLinearFunction )

Vít Hanousek
committed
{
Tomáš Oberhuber
committed
//fill mesh function with linear function (physical center of cell corresponds with its coordinates in grid)
setDof_1D(dof,-1);
linearFunctionEvaluator.evaluateAllEntities(meshFunctionPtr, linearFunctionPtr);
meshFunctionPtr->template synchronize<CommunicatorType>();
auto entity = gridptr->template getEntity< Cell >(0);
entity.refresh();
EXPECT_EQ(meshFunctionPtr->getValue(entity), (*linearFunctionPtr)(entity)) << "Linear function Overlap error on left Edge.";
auto entity2= gridptr->template getEntity< Cell >((dof).getSize()-1);
entity2.refresh();
EXPECT_EQ(meshFunctionPtr->getValue(entity), (*linearFunctionPtr)(entity)) << "Linear function Overlap error on right Edge.";
TEST_F(DistributedGridTest_1D, SynchronizePeriodicNeighborsWithoutMask )
// Setup periodic boundaries
// TODO: I do not know how to do it better with GTEST
typename DistributedGridType::SubdomainOverlapsType lowerOverlap, upperOverlap;
SubdomainOverlapsGetter< GridType, CommunicatorType >::
getOverlaps( distributedGrid, lowerOverlap, upperOverlap, 1, 1 );
distributedGrid->setOverlaps( lowerOverlap, upperOverlap );
distributedGrid->setupGrid(*gridptr);
dof.setSize( gridptr->template getEntitiesCount< Cell >() );
maskDofs.setSize( gridptr->template getEntitiesCount< Cell >() );
meshFunctionPtr->bind( gridptr, dof );
maskPointer->bind( gridptr, maskDofs );
Tomáš Oberhuber
committed
setDof_1D( dof, -rank-1 );
maskDofs.setValue( true );
constFunctionEvaluator.evaluateAllEntities( meshFunctionPtr, constFunctionPtr );
using Synchronizer = decltype( meshFunctionPtr->getSynchronizer() );
meshFunctionPtr->getSynchronizer().setPeriodicBoundariesCopyDirection( Synchronizer::OverlapToBoundary );
Tomáš Oberhuber
committed
meshFunctionPtr->template synchronize<CommunicatorType>( true );
Tomáš Oberhuber
committed
if( rank == 0 )
EXPECT_EQ( dof[ 1 ], -nproc ) << "Left Overlap was filled by wrong process.";
if( rank == nproc-1 )
EXPECT_EQ( dof[ dof.getSize() - 2 ], -1 )<< "Right Overlap was filled by wrong process.";
Tomáš Oberhuber
committed
TEST_F(DistributedGridTest_1D, SynchronizePeriodicNeighborsWithActiveMask )
{
// Setup periodic boundaries
// TODO: I do not know how to do it better with GTEST
typename DistributedGridType::SubdomainOverlapsType lowerOverlap, upperOverlap;
SubdomainOverlapsGetter< GridType, CommunicatorType >::
getOverlaps( distributedGrid, lowerOverlap, upperOverlap, 1, 1 );
distributedGrid->setOverlaps( lowerOverlap, upperOverlap );
distributedGrid->setupGrid(*gridptr);
dof.setSize( gridptr->template getEntitiesCount< Cell >() );
maskDofs.setSize( gridptr->template getEntitiesCount< Cell >() );
meshFunctionPtr->bind( gridptr, dof );
maskPointer->bind( gridptr, maskDofs );
setDof_1D( dof, -rank-1 );
maskDofs.setValue( true );
constFunctionEvaluator.evaluateAllEntities( meshFunctionPtr, constFunctionPtr );
meshFunctionPtr->template synchronize<CommunicatorType>( true, maskPointer );
if( rank == 0 )
EXPECT_EQ( dof[ 1 ], -nproc ) << "Left Overlap was filled by wrong process.";
if( rank == nproc-1 )
EXPECT_EQ( dof[ dof.getSize() - 2 ], -1 )<< "Right Overlap was filled by wrong process.";
Tomáš Oberhuber
committed
}
TEST_F(DistributedGridTest_1D, SynchronizePeriodicNeighborsWithInactiveMaskOnLeft )
{
// Setup periodic boundaries
// TODO: I do not know how to do it better with GTEST
typename DistributedGridType::SubdomainOverlapsType lowerOverlap, upperOverlap;
SubdomainOverlapsGetter< GridType, CommunicatorType >::
getOverlaps( distributedGrid, lowerOverlap, upperOverlap, 1, 1 );
distributedGrid->setOverlaps( lowerOverlap, upperOverlap );
distributedGrid->setupGrid(*gridptr);
dof.setSize( gridptr->template getEntitiesCount< Cell >() );
maskDofs.setSize( gridptr->template getEntitiesCount< Cell >() );
meshFunctionPtr->bind( gridptr, dof );
maskPointer->bind( gridptr, maskDofs );
setDof_1D( dof, -rank-1 );
Tomáš Oberhuber
committed
maskDofs.setValue( true );
maskDofs.setElement( 1, false );
constFunctionEvaluator.evaluateAllEntities( meshFunctionPtr , constFunctionPtr );
meshFunctionPtr->template synchronize<CommunicatorType>( true, maskPointer );
if( rank == 0 )
EXPECT_EQ( dof[ 1 ], 0 ) << "Left Overlap was filled by wrong process.";
if( rank == nproc-1 )
EXPECT_EQ( dof[ dof.getSize() - 2 ], -1 )<< "Right Overlap was filled by wrong process.";
Tomáš Oberhuber
committed
}
TEST_F(DistributedGridTest_1D, SynchronizePeriodicNeighborsWithInactiveMask )
{
// Setup periodic boundaries
// TODO: I do not know how to do it better with GTEST
typename DistributedGridType::SubdomainOverlapsType lowerOverlap, upperOverlap;
SubdomainOverlapsGetter< GridType, CommunicatorType >::
getOverlaps( distributedGrid, lowerOverlap, upperOverlap, 1, 1 );
distributedGrid->setOverlaps( lowerOverlap, upperOverlap );
distributedGrid->setupGrid(*gridptr);
dof.setSize( gridptr->template getEntitiesCount< Cell >() );
maskDofs.setSize( gridptr->template getEntitiesCount< Cell >() );
meshFunctionPtr->bind( gridptr, dof );
maskPointer->bind( gridptr, maskDofs );
setDof_1D( dof, -rank-1 );
Tomáš Oberhuber
committed
maskDofs.setValue( true );
maskDofs.setElement( 1, false );
maskDofs.setElement( dof.getSize() - 2, false );
constFunctionEvaluator.evaluateAllEntities( meshFunctionPtr , constFunctionPtr );
meshFunctionPtr->template synchronize<CommunicatorType>( true, maskPointer );
if( rank == 0 )
EXPECT_EQ( dof[ 1 ], 0 ) << "Left Overlap was filled by wrong process.";
if( rank == nproc-1 )
EXPECT_EQ( dof[ dof.getSize() - 2 ], nproc - 1 )<< "Right Overlap was filled by wrong process.";
TEST_F(DistributedGridTest_1D, SynchronizePeriodicBoundariesLinearTest )
{
// Setup periodic boundaries
// TODO: I do not know how to do it better with GTEST - additional setup
// of the periodic boundaries
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
typename DistributedGridType::SubdomainOverlapsType lowerOverlap, upperOverlap;
SubdomainOverlapsGetter< GridType, CommunicatorType >::
getOverlaps( distributedGrid, lowerOverlap, upperOverlap, 1, 1 );
distributedGrid->setOverlaps( lowerOverlap, upperOverlap );
distributedGrid->setupGrid(*gridptr);
dof.setSize( gridptr->template getEntitiesCount< Cell >() );
meshFunctionPtr->bind( gridptr, dof );
setDof_1D(dof, -rank-1 );
linearFunctionEvaluator.evaluateAllEntities( meshFunctionPtr , linearFunctionPtr );
//TNL_MPI_PRINT( meshFunctionPtr->getData() );
meshFunctionPtr->template synchronize<CommunicatorType>( true );
//TNL_MPI_PRINT( meshFunctionPtr->getData() );
auto entity = gridptr->template getEntity< Cell >( 1 );
auto entity2= gridptr->template getEntity< Cell >( (dof).getSize() - 2 );
entity.refresh();
entity2.refresh();
if( rank == 0 )
EXPECT_EQ( meshFunctionPtr->getValue(entity), -nproc ) << "Linear function Overlap error on left Edge.";
if( rank == nproc - 1 )
EXPECT_EQ( meshFunctionPtr->getValue(entity2), -1 ) << "Linear function Overlap error on right Edge.";
}

Vít Hanousek
committed
#else
TEST(NoMPI, NoTest)
{

Vít Hanousek
committed
ASSERT_TRUE(true) << ":-(";

Vít Hanousek
committed
}
#endif
#endif
#if (defined(HAVE_GTEST) && defined(HAVE_MPI))
#include <sstream>
Tomáš Oberhuber
committed
class MinimalistBufferedPrinter : public ::testing::EmptyTestEventListener {

Vít Hanousek
committed

Vít Hanousek
committed
private:

Vít Hanousek
committed
std::stringstream sout;

Vít Hanousek
committed
public:

Vít Hanousek
committed

Vít Hanousek
committed
// Called before a test starts.
virtual void OnTestStart(const ::testing::TestInfo& test_info) {
sout<< test_info.test_case_name() <<"." << test_info.name() << " Start." <<std::endl;
}
// Called after a failed assertion or a SUCCEED() invocation.
virtual void OnTestPartResult(
const ::testing::TestPartResult& test_part_result) {
sout << (test_part_result.failed() ? "====Failure=== " : "===Success=== ")

Vít Hanousek
committed
<< test_part_result.file_name() << " "

Vít Hanousek
committed
<< test_part_result.line_number() <<std::endl
<< test_part_result.summary() <<std::endl;
}
// Called after a test ends.
virtual void OnTestEnd(const ::testing::TestInfo& test_info)

Vít Hanousek
committed
{
int rank=CommunicatorType::GetRank(CommunicatorType::AllGroup);

Vít Hanousek
committed
sout<< test_info.test_case_name() <<"." << test_info.name() << " End." <<std::endl;

Vít Hanousek
committed
std::cout << rank << ":" << std::endl << sout.str()<< std::endl;
sout.str( std::string() );
sout.clear();

Vít Hanousek
committed
}
};
#endif
#include "../../GtestMissingError.h"

Vít Hanousek
committed
int main( int argc, char* argv[] )
{
#ifdef HAVE_GTEST
::testing::InitGoogleTest( &argc, argv );

Vít Hanousek
committed
#ifdef HAVE_MPI
::testing::TestEventListeners& listeners =
::testing::UnitTest::GetInstance()->listeners();

Vít Hanousek
committed

Vít Hanousek
committed
delete listeners.Release(listeners.default_result_printer());
Tomáš Oberhuber
committed
listeners.Append(new MinimalistBufferedPrinter);

Vít Hanousek
committed
Communicators::ScopedInitializer< CommunicatorType > mpi(argc, argv);

Vít Hanousek
committed
#endif

Vít Hanousek
committed
#else
throw GtestMissingError();
#endif