Briefly, Lloyd relaxation is a technique to smooth out a mesh. The centroid of each cell is computed from its vertex positions, then vertices are placed at the average of their connected cells' centroids.
In the parallel algorithm, an extra ghost layer of cells is exchanged. This allows us to compute the centroids for boundary cells on each processor where they appear; this eliminates the need for one round of data exchange (for those centroids) between processors. New vertex positions must be sent from owning processors to processors sharing those vertices. Convergence is measured as the maximum distance moved by any vertex.
In this implementation, a fixed number of iterations is performed. The final mesh is output to 'lloydfinal.h5m' in the current directory (H5M format must be used since the file is written in parallel).
#ifdef MOAB_HAVE_MPI
#endif
#include <iostream>
#include <sstream>
using namespace std;
int main(
int argc,
char** argv )
{
int num_its = 10;
int report_its = 1;
#ifdef MOAB_HAVE_MPI
MPI_Init( &argc, &argv );
#endif
if( argc > 1 )
{
}
Interface*
mb =
new( std::nothrow ) Core;
if( NULL ==
mb )
return 1;
#ifdef MOAB_HAVE_MPI
ParallelComm* pcomm =
new ParallelComm(
mb, MPI_COMM_WORLD );
int nprocs = pcomm->size();
#else
int nprocs = 1;
#endif
string options;
if( nprocs > 1 )
options = "PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION;PARALLEL_RESOLVE_SHARED_ENTS;"
"PARALLEL_GHOSTS=2.0.1;DEBUG_IO=0;DEBUG_PIO=0";
int def_val = 0;
Range verts, faces, skin_verts;
rval =
mb->get_entities_by_dimension( 0, 2, faces );
MB_CHK_ERR( rval );
rval = skinner.find_skin( 0, faces,
true, skin_verts );
MB_CHK_ERR( rval );
vector< int > fix_tag( skin_verts.size(), 1 );
rval =
mb->tag_set_data( fixed, skin_verts, &fix_tag[0] );
MB_CHK_ERR( rval );
#ifdef MOAB_HAVE_MPI
options = "PARALLEL=WRITE_PART";
#endif
rval =
mb->write_file(
"lloydfinal.h5m", NULL, options.c_str() );
MB_CHK_ERR( rval );
#ifdef MOAB_HAVE_MPI
MPI_Finalize();
#endif
return 0;
}
{
#ifdef MOAB_HAVE_MPI
int nprocs = pcomm->size();
#else
int nprocs = 1;
#endif
vector< double > vcentroids( 3 * verts.size() );
rval =
mb->get_coords( verts, &vcentroids[0] );
MB_CHK_ERR( rval );
rval =
mb->tag_set_data( centroid, verts, &vcentroids[0] );
MB_CHK_ERR( rval );
Range owned_verts, shared_owned_verts;
if( nprocs > 1 )
{
#ifdef MOAB_HAVE_MPI
#endif
}
else
owned_verts = verts;
vector< int > fix_tag( owned_verts.size() );
rval =
mb->tag_get_data( fixed, owned_verts, &fix_tag[0] );
MB_CHK_ERR( rval );
vcentroids.resize( 3 * owned_verts.size() );
rval =
mb->tag_get_data( centroid, owned_verts, &vcentroids[0] );
MB_CHK_ERR( rval );
#ifdef MOAB_HAVE_MPI
rval = pcomm->get_shared_entities( -1, shared_owned_verts, 0,
false,
true );
MB_CHK_ERR( rval );
if( shared_owned_verts.empty() ) shared_owned_verts.insert( *verts.begin() );
#endif
vector< double > fcentroids( 3 * faces.size() );
int nconn;
int f, v;
vector< EntityHandle > adj_faces;
for( int nit = 0; nit < num_its; nit++ )
{
double mxdelta = 0.0;
for( fit = faces.begin(), f = 0; fit != faces.end(); ++fit, f++ )
{
rval =
mb->get_connectivity( *fit, conn, nconn );
MB_CHK_ERR( rval );
rval =
mb->tag_get_data( centroid, conn, nconn, &ctag[0] );
MB_CHK_ERR( rval );
fcentroids[3 * f + 0] = fcentroids[3 * f + 1] = fcentroids[3 * f + 2] = 0.0;
for( v = 0; v < nconn; v++ )
{
fcentroids[3 * f + 0] += ctag[3 * v + 0];
fcentroids[3 * f + 1] += ctag[3 * v + 1];
fcentroids[3 * f + 2] += ctag[3 * v + 2];
}
for( v = 0; v < 3; v++ )
fcentroids[3 * f + v] /= nconn;
}
rval =
mb->tag_set_data( centroid, faces, &fcentroids[0] );
MB_CHK_ERR( rval );
for( vit = owned_verts.begin(), v = 0; vit != owned_verts.end(); ++vit, v++ )
{
if( fix_tag[v] ) continue;
adj_faces.clear();
rval =
mb->get_adjacencies( &( *vit ), 1, 2,
false, adj_faces );
MB_CHK_ERR( rval );
rval =
mb->tag_get_data( centroid, &adj_faces[0], adj_faces.size(), &fcentroids[0] );
MB_CHK_ERR( rval );
double vnew[] = { 0.0, 0.0, 0.0 };
for( f = 0; f < (int)adj_faces.size(); f++ )
{
vnew[0] += fcentroids[3 * f + 0];
vnew[1] += fcentroids[3 * f + 1];
vnew[2] += fcentroids[3 * f + 2];
}
for( f = 0; f < 3; f++ )
vnew[f] /= adj_faces.size();
double delta = ( CartVect( vnew ) - CartVect( &vcentroids[3 * v] ) ).
length();
mxdelta = std::max( delta, mxdelta );
for( f = 0; f < 3; f++ )
vcentroids[3 * v + f] = vnew[f];
}
rval =
mb->tag_set_data( centroid, owned_verts, &vcentroids[0] );
MB_CHK_ERR( rval );
if( nprocs > 1 )
{
#ifdef MOAB_HAVE_MPI
rval = pcomm->exchange_tags( centroid, shared_owned_verts );
MB_CHK_ERR( rval );
#endif
}
if( !( nit % report_its ) )
{
double global_max = mxdelta;
int myrank = 0;
#ifdef MOAB_HAVE_MPI
if( nprocs > 1 ) MPI_Reduce( &mxdelta, &global_max, 1, MPI_DOUBLE, MPI_MAX, 0, pcomm->comm() );
myrank = pcomm->rank();
#endif
if( 1 == nprocs || 0 == myrank ) cout << "Max delta = " << global_max << endl;
}
}
rval =
mb->set_coords( owned_verts, &vcentroids[0] );
MB_CHK_ERR( rval );
}