The program creates two different meshes with configurable partitioning and demonstrates coupling between them using the MBCoupler interface.
#ifdef MOAB_HAVE_MBCOUPLER
#else
#error Requires MOAB to be built with MBCoupler
#endif
using std::string;
double physField(
double x,
double y,
double z )
{
double out = sin( M_PI * x ) * cos( M_PI * y ) * sin( M_PI * z );
return out;
}
int main(
int argc,
char* argv[] )
{
int proc_id = 0, size = 1;
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &proc_id );
MPI_Comm_size( MPI_COMM_WORLD, &size );
Core mcore;
MeshGeneration::BrickOpts opts;
opts.A = opts.B = opts.C = 1;
opts.M = opts.N = opts.K = 1;
opts.blockSize = 4;
opts.xsize = opts.ysize = opts.zsize = 1.;
opts.ui = CartVect( 1., 0, 0. );
opts.uj = CartVect( 0., 1., 0. );
opts.uk = CartVect( 0., 0., 1. );
opts.newMergeMethod = opts.quadratic = opts.keep_skins = opts.tetra = false;
opts.adjEnts = opts.parmerge = false;
opts.GL = 0;
popts.
addOpt<
int >( string(
"blockSize,b" ), string(
"Block size of mesh (default=4)" ), &opts.blockSize );
popts.
addOpt<
int >( string(
"xproc,M" ), string(
"Number of processors in x dir (default=1)" ), &opts.M );
popts.
addOpt<
int >( string(
"yproc,N" ), string(
"Number of processors in y dir (default=1)" ), &opts.N );
popts.
addOpt<
int >( string(
"zproc,K" ), string(
"Number of processors in z dir (default=1)" ), &opts.K );
popts.
addOpt<
int >( string(
"xblocks,A" ), string(
"Number of blocks on a task in x dir (default=2)" ), &opts.A );
popts.
addOpt<
int >( string(
"yblocks,B" ), string(
"Number of blocks on a task in y dir (default=2)" ), &opts.B );
popts.
addOpt<
int >( string(
"zblocks,C" ), string(
"Number of blocks on a task in x dir (default=2)" ), &opts.C );
popts.
addOpt<
double >( string(
"xsize,x" ), string(
"Total size in x direction (default=1.)" ), &opts.xsize );
popts.
addOpt<
double >( string(
"ysize,y" ), string(
"Total size in y direction (default=1.)" ), &opts.ysize );
popts.
addOpt<
double >( string(
"zsize,z" ), string(
"Total size in z direction (default=1.)" ), &opts.zsize );
popts.
addOpt<
void >(
"newMerge,w",
"use new merging method", &opts.newMergeMethod );
popts.
addOpt<
void >(
"quadratic,q",
"use hex 27 elements", &opts.quadratic );
popts.
addOpt<
void >(
"keep_skins,k",
"keep skins with shared entities", &opts.keep_skins );
popts.
addOpt<
void >(
"tetrahedrons,t",
"generate tetrahedrons", &opts.tetra );
popts.
addOpt<
void >(
"faces_edges,f",
"create all faces and edges", &opts.adjEnts );
popts.
addOpt<
int >( string(
"ghost_layers,g" ), string(
"Number of ghost layers (default=0)" ), &opts.GL );
popts.
addOpt<
void >(
"parallel_merge,p",
"use parallel mesh merge, not vertex ID based merge", &opts.parmerge );
double toler = 1.e-6;
popts.
addOpt<
double >( string(
"eps,e" ), string(
"tolerance for coupling, used in locating points" ), &toler );
bool writeMeshes = false;
popts.
addOpt<
void >(
"print,p",
"write meshes", &writeMeshes );
ParallelComm* pc1 =
new ParallelComm(
mb, MPI_COMM_WORLD );
MeshGeneration* mgen1 =
new MeshGeneration(
mb, pc1, fileset1 );
double instance_time = MPI_Wtime();
double current = instance_time;
if( !proc_id ) std::cout <<
" instantiate first mesh " << instance_time -
start_time <<
"\n";
std::string interpTag( "interp_tag" );
Range src_elems;
MB_CHK_ERR( pc1->get_part_entities( src_elems, 3 ) );
Range src_verts;
for(
Range::iterator vit = src_verts.begin(); vit != src_verts.end(); ++vit )
{
double vertPos[3];
double fieldValue =
physField( vertPos[0], vertPos[1], vertPos[2] );
}
double setTag_time = MPI_Wtime();
if( !proc_id ) std::cout << " set tag " << setTag_time - current;
current = instance_time;
int tmp1 = opts.K;
opts.K = opts.M;
opts.M = tmp1;
opts.tetra = !opts.tetra;
opts.blockSize++;
ParallelComm* pc2 =
new ParallelComm(
mb, MPI_COMM_WORLD );
MeshGeneration* mgen2 =
new MeshGeneration(
mb, pc2, fileset2 );
double instance_second = MPI_Wtime();
if( !proc_id ) std::cout << " instance second mesh" << instance_second - current << "\n";
current = instance_second;
if( writeMeshes )
{
1 ),
"Can't write in parallel mesh 1" );
1 ),
"Can't write in parallel mesh 1" );
double write_files = MPI_Wtime();
if( !proc_id ) std::cout << " write files " << write_files - current << "\n";
current = write_files;
}
Coupler mbc(
mb, pc1, src_elems, 0 );
double instancecoupler = MPI_Wtime();
if( !proc_id ) std::cout << " instance coupler " << instancecoupler - current << "\n";
current = instancecoupler;
std::vector< double > vpos;
int numPointsOfInterest = 0;
Range targ_elems;
Range targ_verts;
MB_CHK_ERR( pc2->get_part_entities( targ_elems, 3 ) );
Range tmp_verts;
targ_verts =
subtract( targ_verts, tmp_verts );
numPointsOfInterest = (int)targ_verts.size();
vpos.resize( 3 * targ_verts.size() );
MB_CHK_ERR( mbc.locate_points( &vpos[0], numPointsOfInterest, 0, toler ) );
double locatetime = MPI_Wtime();
if( !proc_id ) std::cout << " locate points: " << locatetime - current << "\n";
current = locatetime;
std::vector< double > field( numPointsOfInterest );
MB_CHK_ERR( mbc.interpolate( method, interpTag, &field[0] ) );
double err_max = 0;
for( int i = 0; i < numPointsOfInterest; i++ )
{
double trval =
physField( vpos[3 * i], vpos[3 * i + 1], vpos[3 * i + 2] );
double err2 = fabs( trval - field[i] );
if( err2 > err_max ) err_max = err2;
}
double interpolateTime = MPI_Wtime();
if( !proc_id ) std::cout << " interpolate points: " << interpolateTime - current << "\n";
current = interpolateTime;
double gerr;
MPI_Allreduce( &err_max, &gerr, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD );
if( 0 == proc_id ) std::cout << "max err " << gerr << "\n";
delete mgen1;
delete mgen2;
MPI_Finalize();
return 0;
}