|
MOAB: Mesh Oriented datABase
(version 5.4.1)
|
#include <iostream>#include <vector>#include "moab/Core.hpp"#include "OfflineMap.h"#include "moab/Remapping/TempestRemapper.hpp"#include "moab/Remapping/TempestOnlineMap.hpp"#include "moab/ParallelComm.hpp"#include "Internals.hpp"#include "TestRunner.hpp"#include <netcdf.h>#include <netcdf_par.h>
Include dependency graph for test_mapweights_bcast.cpp:Go to the source code of this file.
Defines | |
| #define | IS_BUILDING_MB |
| #define | NCERROREXIT(err, MSG) |
Functions | |
| void | test_tempest_map_bcast () |
| void | read_buffered_map () |
| void | read_map_from_disk () |
| int | main (int argc, char **argv) |
Variables | |
| std::string | inMapFilename = "" |
| #define IS_BUILDING_MB |
Definition at line 24 of file test_mapweights_bcast.cpp.
| #define NCERROREXIT | ( | err, | |
| MSG | |||
| ) |
if( err ) \ { \ std::cout << "Error (" << ( err ) << "): " << ( MSG ); \ std::cout << "\nAborting with message: " << nc_strerror( err ) << "... \n"; \ return; \ }
Definition at line 62 of file test_mapweights_bcast.cpp.
| int main | ( | int | argc, |
| char ** | argv | ||
| ) |
Definition at line 41 of file test_mapweights_bcast.cpp.
References inMapFilename, read_buffered_map(), read_map_from_disk(), REGISTER_TEST, PointInVol::result, RUN_TESTS, and test_tempest_map_bcast().
{
if( argc > 1 )
inMapFilename = std::string( argv[1] );
else
inMapFilename = TestDir + "unittest/outCS5ICOD5_map.nc";
REGISTER_TEST( test_tempest_map_bcast );
REGISTER_TEST( read_buffered_map );
REGISTER_TEST( read_map_from_disk );
#ifdef MOAB_HAVE_MPI
MPI_Init( &argc, &argv );
#endif
int result = RUN_TESTS( argc, argv );
#ifdef MOAB_HAVE_MPI
MPI_Finalize();
#endif
return result;
}
| void read_buffered_map | ( | ) |
Perform a series of checks to ensure that the local maps in each process still preserve map properties Let us run our usual tests to verify that the map data has been distributed correctly 1) Consistency check -- row sum = 1.0 2) Disable conservation checks that require global column sums (and hence more communication/reduction) 3) Perform monotonicity check and ensure failures globally are same as serial case
Definition at line 70 of file test_mapweights_bcast.cpp.
References CHECK_EQUAL, moab::error(), inMapFilename, MPI_COMM_WORLD, rank, and size.
Referenced by main().
{
NcError error( NcError::silent_nonfatal );
// Define our total buffer size to use
NcFile* ncMap = NULL;
NcVar *varRow = NULL, *varCol = NULL, *varS = NULL;
#ifdef MOAB_HAVE_MPI
int mpierr = 0;
const int rootProc = 0;
#endif
// Main inputs;
// 1. Map Filename
// 2. Ownership info from the processes to be gathered on root
const int nBufferSize = 64 * 1024; // 64 KB
const int nNNZBytes = 2 * sizeof( int ) + sizeof( double );
const int nMaxEntries = nBufferSize / nNNZBytes;
int nA = 0, nB = 0, nVA = 0, nVB = 0, nS = 0;
double dTolerance = 1e-08;
int nprocs = 1, rank = 0;
#ifdef MOAB_HAVE_MPI
MPI_Comm commW = MPI_COMM_WORLD;
MPI_Comm_size( commW, &nprocs );
MPI_Comm_rank( commW, &rank );
#endif
#ifdef MOAB_HAVE_MPI
if( rank == rootProc )
#endif
{
ncMap = new NcFile( inMapFilename.c_str(), NcFile::ReadOnly );
if( !ncMap->is_valid() )
{
_EXCEPTION1( "Unable to open input map file \"%s\"", inMapFilename.c_str() );
}
// Source and Target mesh resolutions
NcDim* dimNA = ncMap->get_dim( "n_a" );
if( dimNA == NULL )
{
_EXCEPTIONT( "Input map missing dimension \"n_a\"" );
}
else
nA = dimNA->size();
NcDim* dimNB = ncMap->get_dim( "n_b" );
if( dimNB == NULL )
{
_EXCEPTIONT( "Input map missing dimension \"n_b\"" );
}
else
nB = dimNB->size();
NcDim* dimNVA = ncMap->get_dim( "nv_a" );
if( dimNVA == NULL )
{
_EXCEPTIONT( "Input map missing dimension \"nv_a\"" );
}
else
nVA = dimNVA->size();
NcDim* dimNVB = ncMap->get_dim( "nv_b" );
if( dimNVB == NULL )
{
_EXCEPTIONT( "Input map missing dimension \"nv_b\"" );
}
else
nVB = dimNVB->size();
// Read SparseMatrix entries
NcDim* dimNS = ncMap->get_dim( "n_s" );
if( dimNS == NULL )
{
_EXCEPTION1( "Map file \"%s\" does not contain dimension \"n_s\"", inMapFilename.c_str() );
}
else
nS = dimNS->size(); // store total number of nonzeros
varRow = ncMap->get_var( "row" );
if( varRow == NULL )
{
_EXCEPTION1( "Map file \"%s\" does not contain variable \"row\"", inMapFilename.c_str() );
}
varCol = ncMap->get_var( "col" );
if( varCol == NULL )
{
_EXCEPTION1( "Map file \"%s\" does not contain variable \"col\"", inMapFilename.c_str() );
}
varS = ncMap->get_var( "S" );
if( varS == NULL )
{
_EXCEPTION1( "Map file \"%s\" does not contain variable \"S\"", inMapFilename.c_str() );
}
}
// const int nTotalBytes = nS * nNNZBytes;
int nEntriesRemaining = nS;
int nBufferedReads = static_cast< int >( ceil( ( 1.0 * nS ) / ( 1.0 * nMaxEntries ) ) );
int runData[6] = { nA, nB, nVA, nVB, nS, nBufferedReads };
mpierr = MPI_Bcast( runData, 6, MPI_INT, rootProc, commW );
CHECK_EQUAL( mpierr, 0 );
#ifdef MOAB_HAVE_MPI
if( rank != rootProc )
{
nA = runData[0];
nB = runData[1];
nVA = runData[2];
nVB = runData[3];
nS = runData[4];
nBufferedReads = runData[5];
}
else
printf( "Global parameters: nA = %d, nB = %d, nS = %d\n", nA, nB, nS );
#else
printf( "Global parameters: nA = %d, nB = %d, nS = %d\n", nA, nB, nS );
#endif
std::vector< int > rowOwnership( nprocs );
int nGRowPerPart = nB / nprocs;
int nGRowRemainder = nB % nprocs; // Keep the remainder in root
rowOwnership[0] = nGRowPerPart + nGRowRemainder;
for( int ip = 1, roffset = rowOwnership[0]; ip < nprocs; ++ip )
{
roffset += nGRowPerPart;
rowOwnership[ip] = roffset;
}
// Let us declare the map object for every process
OfflineMap mapRemap;
SparseMatrix< double >& sparseMatrix = mapRemap.GetSparseMatrix();
#ifdef MOAB_HAVE_MPI
if( rank == rootProc )
#endif
printf( "Parameters: nA=%d, nB=%d, nVA=%d, nVB=%d, nS=%d, nNNZBytes = %d, nBufferedReads = %d\n", nA, nB, nVA,
nVB, nS, nNNZBytes, nBufferedReads );
std::map< int, int > rowMap, colMap;
int rindexMax = 0, cindexMax = 0;
long offset = 0;
/* Split the rows and send to processes in chunks
Let us start the buffered read */
for( int iRead = 0; iRead < nBufferedReads; ++iRead )
{
// pointers to the data
DataArray1D< int > vecRow;
DataArray1D< int > vecCol;
DataArray1D< double > vecS;
std::vector< std::vector< int > > dataPerProcess( nprocs );
std::vector< int > nDataPerProcess( nprocs, 0 );
for( int ip = 0; ip < nprocs; ++ip )
dataPerProcess[ip].reserve( std::max( 100, nMaxEntries / nprocs ) );
#ifdef MOAB_HAVE_MPI
if( rank == rootProc )
#endif
{
int nLocSize = std::min( nEntriesRemaining, static_cast< int >( ceil( nBufferSize * 1.0 / nNNZBytes ) ) );
printf( "Reading file: elements %ld to %ld\n", offset, offset + nLocSize );
// Allocate and resize based on local buffer size
vecRow.Allocate( nLocSize );
vecCol.Allocate( nLocSize );
vecS.Allocate( nLocSize );
varRow->set_cur( (long)( offset ) );
varRow->get( &( vecRow[0] ), nLocSize );
varCol->set_cur( (long)( offset ) );
varCol->get( &( vecCol[0] ), nLocSize );
varS->set_cur( (long)( offset ) );
varS->get( &( vecS[0] ), nLocSize );
// Decrement vecRow and vecCol
for( size_t i = 0; i < vecRow.GetRows(); i++ )
{
vecRow[i]--;
vecCol[i]--;
// TODO: Fix this linear search to compute process ownership
int pOwner = -1;
if( rowOwnership[0] > vecRow[i] )
pOwner = 0;
else
{
for( int ip = 1; ip < nprocs; ++ip )
{
if( rowOwnership[ip - 1] <= vecRow[i] && rowOwnership[ip] > vecRow[i] )
{
pOwner = ip;
break;
}
}
}
assert( pOwner >= 0 && pOwner < nprocs );
dataPerProcess[pOwner].push_back( i );
}
offset += nLocSize;
nEntriesRemaining -= nLocSize;
for( int ip = 0; ip < nprocs; ++ip )
nDataPerProcess[ip] = dataPerProcess[ip].size();
}
// Communicate the number of DoF data to expect from root
int nEntriesComm = 0;
mpierr = MPI_Scatter( nDataPerProcess.data(), 1, MPI_INT, &nEntriesComm, 1, MPI_INT, rootProc, commW );
CHECK_EQUAL( mpierr, 0 );
#ifdef MOAB_HAVE_MPI
if( rank == rootProc )
#endif
{
std::vector< MPI_Request > cRequests;
std::vector< MPI_Status > cStats( 2 * nprocs - 2 );
cRequests.reserve( 2 * nprocs - 2 );
// First send out all the relevant data buffers to other process
std::vector< std::vector< int > > dataRowColsAll( nprocs );
std::vector< std::vector< double > > dataEntriesAll( nprocs );
for( int ip = 1; ip < nprocs; ++ip )
{
const int nDPP = nDataPerProcess[ip];
if( nDPP > 0 )
{
std::vector< int >& dataRowCols = dataRowColsAll[ip];
dataRowCols.resize( 2 * nDPP );
std::vector< double >& dataEntries = dataEntriesAll[ip];
dataEntries.resize( nDPP );
for( int ij = 0; ij < nDPP; ++ij )
{
dataRowCols[ij * 2] = vecRow[dataPerProcess[ip][ij]];
dataRowCols[ij * 2 + 1] = vecCol[dataPerProcess[ip][ij]];
dataEntries[ij] = vecS[dataPerProcess[ip][ij]];
}
MPI_Request rcsend, dsend;
mpierr = MPI_Isend( dataRowCols.data(), 2 * nDPP, MPI_INT, ip, iRead * 1000, commW, &rcsend );
CHECK_EQUAL( mpierr, 0 );
mpierr = MPI_Isend( dataEntries.data(), nDPP, MPI_DOUBLE, ip, iRead * 1000 + 1, commW, &dsend );
CHECK_EQUAL( mpierr, 0 );
cRequests.push_back( rcsend );
cRequests.push_back( dsend );
}
}
// Next perform all necessary local work while we wait for the buffers to be sent out
// Compute an offset for the rows and columns by creating a local to global mapping for rootProc
int rindex = 0, cindex = 0;
assert( dataPerProcess[0].size() - nEntriesComm == 0 ); // sanity check
for( int i = 0; i < nEntriesComm; ++i )
{
const int& vecRowValue = vecRow[dataPerProcess[0][i]];
const int& vecColValue = vecCol[dataPerProcess[0][i]];
std::map< int, int >::iterator riter = rowMap.find( vecRowValue );
if( riter == rowMap.end() )
{
rowMap[vecRowValue] = rindexMax;
rindex = rindexMax;
rindexMax++;
}
else
rindex = riter->second;
std::map< int, int >::iterator citer = colMap.find( vecColValue );
if( citer == colMap.end() )
{
colMap[vecColValue] = cindexMax;
cindex = cindexMax;
cindexMax++;
}
else
cindex = citer->second;
sparseMatrix( rindex, cindex ) = vecS[i];
}
// Wait until all communication is pushed out
mpierr = MPI_Waitall( cRequests.size(), cRequests.data(), cStats.data() );
CHECK_EQUAL( mpierr, 0 );
} // if( rank == rootProc )
#ifdef MOAB_HAVE_MPI
else
{
if( nEntriesComm > 0 )
{
MPI_Request cRequests[2];
MPI_Status cStats[2];
/* code */
// create buffers to receive the data from root process
std::vector< int > dataRowCols( 2 * nEntriesComm );
vecRow.Allocate( nEntriesComm );
vecCol.Allocate( nEntriesComm );
vecS.Allocate( nEntriesComm );
/* TODO: combine row and column scatters together. Save one communication by better packing */
// Scatter the rows, cols and entries to the processes according to the partition
mpierr = MPI_Irecv( dataRowCols.data(), 2 * nEntriesComm, MPI_INT, rootProc, iRead * 1000, commW,
&cRequests[0] );
CHECK_EQUAL( mpierr, 0 );
mpierr = MPI_Irecv( vecS, nEntriesComm, MPI_DOUBLE, rootProc, iRead * 1000 + 1, commW, &cRequests[1] );
CHECK_EQUAL( mpierr, 0 );
// Wait until all communication is pushed out
mpierr = MPI_Waitall( 2, cRequests, cStats );
CHECK_EQUAL( mpierr, 0 );
// Compute an offset for the rows and columns by creating a local to global mapping
int rindex = 0, cindex = 0;
for( int i = 0; i < nEntriesComm; ++i )
{
const int& vecRowValue = dataRowCols[i * 2];
const int& vecColValue = dataRowCols[i * 2 + 1];
std::map< int, int >::iterator riter = rowMap.find( vecRowValue );
if( riter == rowMap.end() )
{
rowMap[vecRowValue] = rindexMax;
rindex = rindexMax;
rindexMax++;
}
else
rindex = riter->second;
vecRow[i] = rindex;
std::map< int, int >::iterator citer = colMap.find( vecColValue );
if( citer == colMap.end() )
{
colMap[vecColValue] = cindexMax;
cindex = cindexMax;
cindexMax++;
}
else
cindex = citer->second;
vecCol[i] = cindex;
sparseMatrix( rindex, cindex ) = vecS[i];
}
// clear the local buffer
dataRowCols.clear();
} // if( nEntriesComm > 0 )
} // if( rank != rootProc )
MPI_Barrier( commW );
#endif
}
#ifdef MOAB_HAVE_MPI
if( rank == rootProc )
#endif
{
assert( nEntriesRemaining == 0 );
ncMap->close();
}
/**
* Perform a series of checks to ensure that the local maps in each process still preserve map properties
* Let us run our usual tests to verify that the map data has been distributed correctly
* 1) Consistency check -- row sum = 1.0
* 2) Disable conservation checks that require global column sums (and hence more communication/reduction)
* 3) Perform monotonicity check and ensure failures globally are same as serial case
*/
printf( "Rank %d: sparsematrix size = %d x %d\n", rank, sparseMatrix.GetRows(), sparseMatrix.GetColumns() );
// consistency: row sums
{
int isConsistentP = mapRemap.IsConsistent( dTolerance );
if( 0 != isConsistentP )
{
printf( "Rank %d failed consistency checks...\n", rank );
}
CHECK_EQUAL( 0, isConsistentP );
}
// conservation: we will disable this conservation check for now.
// int isConservativeP = mapRemap.IsConservative( dTolerance );
// CHECK_EQUAL( 0, isConservativeP );
// monotonicity: local failures
{
int isMonotoneP = mapRemap.IsMonotone( dTolerance );
// Accumulate sum of failures to ensure that it is exactly same as serial case
int isMonotoneG;
mpierr = MPI_Allreduce( &isMonotoneP, &isMonotoneG, 1, MPI_INT, MPI_SUM, commW );
CHECK_EQUAL( mpierr, 0 );
// 4600 monotonicity fails in serial and parallel for the test map file
CHECK_EQUAL( 4600, isMonotoneG );
}
delete ncMap;
return;
}
| void read_map_from_disk | ( | ) |
Definition at line 481 of file test_mapweights_bcast.cpp.
References CHECK_EQUAL, moab::TempestRemapper::constructEdgeMap, moab::error(), ErrorCode, moab::TempestRemapper::initialize(), moab::TempestOnlineMap::IsConsistent(), moab::TempestOnlineMap::IsMonotone(), mb, MB_SUCCESS, moab::TempestRemapper::meshValidate, MPI_COMM_WORLD, and moab::TempestOnlineMap::ReadParallelMap().
Referenced by main().
{
moab::ErrorCode rval;
NcError error( NcError::verbose_nonfatal );
MPI_Comm commW = MPI_COMM_WORLD;
std::vector< int > tmp_owned_ids;
double dTolerance = 1e-08;
std::string remap_weights_filename = TestDir + "unittest/outCS5ICOD5_map.nc";
moab::Interface* mb = new moab::Core();
moab::ParallelComm pcomm( mb, commW );
moab::TempestRemapper remapper( mb, &pcomm );
remapper.meshValidate = true;
remapper.constructEdgeMap = true;
// Do not create new filesets; Use the sets from our respective applications
remapper.initialize( false );
moab::TempestOnlineMap onlinemap( &remapper );
rval = onlinemap.ReadParallelMap( remap_weights_filename.c_str(), tmp_owned_ids, true );
CHECK_EQUAL( rval, moab::MB_SUCCESS );
// consistency: row sums
int isConsistentP = onlinemap.IsConsistent( dTolerance );
CHECK_EQUAL( 0, isConsistentP );
// conservation: we will disable this conservation check for now
// since we do not have information about source and target areas
// to accurately decipher conservation data satisfaction
// int isConservativeP = onlinemap.IsConservative( dTolerance );
// CHECK_EQUAL( 0, isConservativeP );
// monotonicity: global failures
int isMonotoneP = onlinemap.IsMonotone( dTolerance );
// Accumulate sum of failures to ensure that it is exactly same as serial case
// 4600 fails in serial. What about parallel ? Check and confirm.
CHECK_EQUAL( 4600, isMonotoneP );
}
| void test_tempest_map_bcast | ( | ) |
Perform a series of checks to ensure that the local maps in each process still preserve map properties Let us run our usual tests to verify that the map data has been distributed correctly 1) Consistency check -- row sum = 1.0 2) Disable conservation checks that require global column sums (and hence more communication/reduction) 3) Perform monotonicity check and ensure failures globally are same as serial case
Definition at line 523 of file test_mapweights_bcast.cpp.
References CHECK_EQUAL, CHECK_REAL_EQUAL, moab::error(), inMapFilename, MPI_COMM_WORLD, rank, and moab::sum().
Referenced by main().
{
/*
*
* Load mapping file generated with CS5 and ICOD5 meshes with FV-FV
* projection for field data. It has following attributes:
*
* Analyzing map
* ..Per-dof consistency (tol 1.00000e-08).. PASS
* ..Per-dof conservation (tol 1.00000e-08).. PASS
* ..Weights within range [-10,+10].. Done
* ..
* .. Total nonzero entries: 8976
* .. Column index min/max: 1 / 150 (150 source dofs)
* .. Row index min/max: 1 / 252 (252 target dofs)
* .. Source area / 4pi: 9.999999999991666e-01
* .. Source area min/max: 7.758193626656797e-02 / 9.789674024202324e-02
* .. Target area / 4pi: 9.999999999999928e-01
* .. Target area min/max: 3.418848585325412e-02 / 5.362041648788460e-02
* .. Source frac min/max: 9.999999999997851e-01 / 1.000000000003865e+00
* .. Target frac min/max: 9.999999999993099e-01 / 1.000000000000784e+00
* .. Map weights min/max: -2.062659472710135e-01 / 1.143815352351317e+00
* .. Row sums min/max: 9.999999999993099e-01 / 1.000000000000784e+00
* .. Consist. err min/max: -6.901146321069973e-13 / 7.838174553853605e-13
* .. Col wt.sums min/max: 9.999999999997854e-01 / 1.000000000003865e+00
* .. Conserv. err min/max: -2.146061106600428e-13 / 3.865352482534945e-12
* ..
* ..Histogram of nonzero entries in sparse matrix
* ....Column 1: Number of nonzero entries (bin minimum)
* ....Column 2: Number of columns with that many nonzero values
* ....Column 3: Number of rows with that many nonzero values
* ..[[25, 0, 2],[29, 0, 8],[30, 0, 10],[31, 150, 232]]
* ..
* ..Histogram of weights
* ....Column 1: Lower bound on weights
* ....Column 2: Upper bound on weights
* ....Column 3: # of weights in that bin
* ..[[-1, 0, 4577],[0, 1, 4365],[1, 2, 34]]
*
*/
NcError error( NcError::silent_nonfatal );
MPI_Comm commW = MPI_COMM_WORLD;
const int rootProc = 0;
const std::string outFilename = inMapFilename;
double dTolerance = 1e-08;
int mpierr = 0;
int nprocs, rank;
MPI_Comm_size( MPI_COMM_WORLD, &nprocs );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
const double dFillValueOverride = 0.0;
OfflineMap mapRemap;
if( rank == 0 )
{
std::cout << "Reading file: " << outFilename << std::endl;
mapRemap.Read( outFilename );
mapRemap.SetFillValueOverrideDbl( dFillValueOverride );
mapRemap.SetFillValueOverride( static_cast< float >( dFillValueOverride ) );
int isConsistent = mapRemap.IsConsistent( dTolerance );
CHECK_EQUAL( 0, isConsistent );
int isConservative = mapRemap.IsConservative( dTolerance );
CHECK_EQUAL( 0, isConservative );
int isMonotone = mapRemap.IsMonotone( dTolerance );
CHECK_EQUAL( 4600, isMonotone );
// verify that the source and target mesh areas are equal
DataArray1D< double >& srcAreas = mapRemap.GetSourceAreas();
DataArray1D< double >& tgtAreas = mapRemap.GetTargetAreas();
double totSrcArea = 0.0;
for( size_t i = 0; i < srcAreas.GetRows(); ++i )
totSrcArea += srcAreas[i];
double totTgtArea = 0.0;
for( size_t i = 0; i < tgtAreas.GetRows(); ++i )
totTgtArea += tgtAreas[i];
CHECK_REAL_EQUAL( totSrcArea, totTgtArea, 1e-10 );
}
MPI_Barrier( commW );
SparseMatrix< double >& sparseMatrix = mapRemap.GetSparseMatrix();
// Get the row, col and entry data tupl
// Retrieve all data from the map operator on root process
DataArray1D< int > dataRowsGlobal, dataColsGlobal;
DataArray1D< double > dataEntriesGlobal;
if( rank == 0 )
{
sparseMatrix.GetEntries( dataRowsGlobal, dataColsGlobal, dataEntriesGlobal );
std::cout << "Total NNZ in remap matrix = " << dataRowsGlobal.GetRows() << std::endl;
}
int *rg = nullptr, *cg = nullptr;
double* de = nullptr;
int nMapGlobalRowCols[3] = { sparseMatrix.GetRows(), sparseMatrix.GetColumns(),
static_cast< int >( dataEntriesGlobal.GetRows() ) };
/* split the rows and send to processes in chunks */
std::vector< int > rowAllocation;
std::vector< int > sendCounts;
std::vector< int > displs;
const int NDATA = 3;
if( rank == 0 )
{
rg = dataRowsGlobal;
cg = dataColsGlobal;
de = dataEntriesGlobal;
// Let us do a trivial partitioning of the row data
rowAllocation.resize( nprocs * NDATA );
displs.resize( nprocs );
sendCounts.resize( nprocs );
int nRowPerPart = nMapGlobalRowCols[0] / nprocs;
int remainder = nMapGlobalRowCols[0] % nprocs; // Keep the remainder in root
// printf( "nRowPerPart = %d, remainder = %d\n", nRowPerPart, remainder );
int sum = 0;
for( int i = 0; i < nprocs; ++i )
{
rowAllocation[i * NDATA] = nRowPerPart + ( i == 0 ? remainder : 0 );
rowAllocation[i * NDATA + 1] = std::find( rg, rg + dataRowsGlobal.GetRows(), sum ) - rg;
sum += rowAllocation[i * NDATA];
displs[i] = rowAllocation[i * NDATA + 1];
}
for( int i = 0; i < nprocs - 1; ++i )
{
rowAllocation[i * NDATA + 2] = rowAllocation[( i + 1 ) * NDATA + 1] - rowAllocation[i * NDATA + 1];
sendCounts[i] = rowAllocation[i * NDATA + 2];
}
rowAllocation[( nprocs - 1 ) * NDATA + 2] = nMapGlobalRowCols[2] - displs[nprocs - 1];
sendCounts[nprocs - 1] = rowAllocation[( nprocs - 1 ) * NDATA + 2];
// for( int i = 0; i < nprocs; i++ )
// printf( "sendcounts[%d] = %d, %d, %d\tdispls[%d] = %d, %d\n", i, rowAllocation[i * NDATA],
// rowAllocation[i * NDATA + 1], rowAllocation[i * NDATA + 2], i, displs[i], sendCounts[i] );
}
mpierr = MPI_Bcast( nMapGlobalRowCols, 3, MPI_INT, rootProc, commW );
CHECK_EQUAL( mpierr, 0 );
int allocationSize[NDATA] = { 0, 0, 0 };
mpierr = MPI_Scatter( rowAllocation.data(), NDATA, MPI_INT, &allocationSize, NDATA, MPI_INT, rootProc, commW );
CHECK_EQUAL( mpierr, 0 );
// create buffers to receive the data from root process
DataArray1D< int > dataRows, dataCols;
DataArray1D< double > dataEntries;
dataRows.Allocate( allocationSize[2] );
dataCols.Allocate( allocationSize[2] );
dataEntries.Allocate( allocationSize[2] );
/* TODO: combine row and column scatters together. Save one communication by better packing */
// Scatter the rows, cols and entries to the processes according to the partition
mpierr = MPI_Scatterv( rg, sendCounts.data(), displs.data(), MPI_INT, (int*)( dataRows ), dataRows.GetByteSize(),
MPI_INT, rootProc, commW );
CHECK_EQUAL( mpierr, 0 );
mpierr = MPI_Scatterv( cg, sendCounts.data(), displs.data(), MPI_INT, (int*)( dataCols ), dataCols.GetByteSize(),
MPI_INT, rootProc, commW );
CHECK_EQUAL( mpierr, 0 );
mpierr = MPI_Scatterv( de, sendCounts.data(), displs.data(), MPI_DOUBLE, (double*)( dataEntries ),
dataEntries.GetByteSize(), MPI_DOUBLE, rootProc, commW );
CHECK_EQUAL( mpierr, 0 );
// Compute an offset for the rows and columns by creating a local to global mapping
std::vector< int > rowMap, colMap;
for( int i = 0; i < allocationSize[2]; ++i )
{
int rindex, cindex;
std::vector< int >::iterator riter = std::find( rowMap.begin(), rowMap.end(), dataRows[i] );
if( riter == rowMap.end() )
{
rowMap.push_back( dataRows[i] );
rindex = rowMap.size() - 1;
}
else
rindex = riter - rowMap.begin();
dataRows[i] = rindex;
std::vector< int >::iterator citer = std::find( colMap.begin(), colMap.end(), dataCols[i] );
if( citer == colMap.end() )
{
colMap.push_back( dataCols[i] );
cindex = colMap.size() - 1;
}
else
cindex = citer - colMap.begin();
dataCols[i] = cindex;
}
// Now set the data received from root onto the sparse matrix
sparseMatrix.SetEntries( dataRows, dataCols, dataEntries );
/**
* Perform a series of checks to ensure that the local maps in each process still preserve map properties
* Let us run our usual tests to verify that the map data has been distributed correctly
* 1) Consistency check -- row sum = 1.0
* 2) Disable conservation checks that require global column sums (and hence more communication/reduction)
* 3) Perform monotonicity check and ensure failures globally are same as serial case
*/
// consistency: row sums
int isConsistentP = mapRemap.IsConsistent( dTolerance );
CHECK_EQUAL( 0, isConsistentP );
// conservation: we will disable this conservation check for now.
// int isConservativeP = mapRemap.IsConservative( dTolerance );
// CHECK_EQUAL( 0, isConservativeP );
// monotonicity: local failures
int isMonotoneP = mapRemap.IsMonotone( dTolerance );
// Accumulate sum of failures to ensure that it is exactly same as serial case
int isMonotoneG;
mpierr = MPI_Allreduce( &isMonotoneP, &isMonotoneG, 1, MPI_INT, MPI_SUM, commW );
CHECK_EQUAL( mpierr, 0 );
// 4600 fails in serial. What about parallel ? Check and confirm.
CHECK_EQUAL( 4600, isMonotoneG );
return;
}
| std::string inMapFilename = "" |
Definition at line 35 of file test_mapweights_bcast.cpp.
Referenced by main(), read_buffered_map(), and test_tempest_map_bcast().