This example demonstrates computation of dual polygonal mesh from primal triangulation. It shows how to load a triangular mesh from a file, compute the dual polygonal mesh of a triangulation, handle spherical surface triangulations, create dual vertices at triangle centroids, generate dual polygons around primal vertices, orient dual polygons correctly on spherical surfaces, preserve global IDs during dual mesh construction, and write the dual mesh to a new file.
The dual mesh computation is particularly useful for finite volume methods and other applications requiring dual grid structures.
To run: ComputeTriDual input_file output_file An example to demonstrate computing the dual polygonal grid of a triangulation on a spherical surface.
#include <iostream>
#include <vector>
#ifdef MOAB_HAVE_MPI
#endif
{
MB_CHK_SET_ERR(
mb->get_connectivity( cells, verts ),
"Failed to get connectivity" );
std::vector< double* > ccenters;
std::vector< int > gids( cells.
size() );
MB_CHK_SET_ERR(
mb->get_coords( cells, ccenters[0], ccenters[1], ccenters[2] ),
"Failed to get coordinates" );
MB_CHK_SET_ERR(
mb->tag_get_data( gidTag, cells, &gids[0] ),
"Can't set global_id tag" );
MB_CHK_SET_ERR(
mb->add_entities( dual_set, dualverts ),
"Can't add entities" );
MB_CHK_SET_ERR(
mb->tag_set_data( gidTag, dualverts, &gids[0] ),
"Can't set global_id tag" );
#define CC( ind ) moab::CartVect( ccenters[0][ind], ccenters[1][ind], ccenters[2][ind] )
#define CCXMY( ind, cv ) \
moab::CartVect( ccenters[0][ind] - ( cv )[0], ccenters[1][ind] - ( cv )[1], ccenters[2][ind] - ( cv )[2] )
std::map< size_t, std::vector< moab::EntityHandle > > polygonConn;
{
std::vector< moab::EntityHandle > adjs;
MB_CHK_SET_ERR(
mb->get_adjacencies( &vtx, 1, 2,
true, adjs ),
"Failed to get adjacencies" );
const size_t nEdges = adjs.size();
double vxyz[3];
double dNode0Mag = node0.
length();
std::vector< double > dAngles;
dAngles.resize( nEdges );
dAngles[0] = 0.0;
for( size_t j = 1; j < nEdges; j++ )
{
double dNodeDiffMag = nodeDiff.
length();
double dSide = nodeCross % nodeDiff;
double dDotNorm = ( node0 % nodeDiff ) / ( dNode0Mag * dNodeDiffMag );
if( dDotNorm > 1.0 )
{
dDotNorm = 1.0;
}
dAngles[j] = acos( dDotNorm );
if( dSide > 0.0 )
{
dAngles[j] = -dAngles[j] + 2.0 * M_PI;
}
}
std::vector< moab::EntityHandle >&
face = polygonConn[nEdges];
if(
face.size() == 0 )
face.reserve( nEdges * verts.
size() / 4 );
face.push_back( dualverts[adjs[0] - svtx] );
double dCurrentAngle = 0.0;
for( size_t j = 1; j < nEdges; j++ )
{
int ixNextNode = 1;
double dNextAngle = 2.0 * M_PI;
for( size_t k = 1; k < nEdges; k++ )
{
if( ( dAngles[k] > dCurrentAngle ) && ( dAngles[k] < dNextAngle ) )
{
ixNextNode = k;
dNextAngle = dAngles[k];
}
}
face.push_back( dualverts[adjs[ixNextNode] - svtx] );
dCurrentAngle = dNextAngle;
}
}
std::map< size_t, std::vector< moab::EntityHandle > >::iterator eit;
for( eit = polygonConn.begin(); eit != polygonConn.end(); ++eit )
{
const size_t nVPerE = eit->first;
const size_t nElePerType = static_cast< int >( eit->second.size() / nVPerE );
"Can't get element connectivity" );
std::copy( eit->second.begin(), eit->second.end(), conn );
eit->second.clear();
moab::Range mbcells( starte, starte + nElePerType - 1 );
dualcells.
merge( mbcells );
}
MB_CHK_SET_ERR(
mb->add_entities( dual_set, dualcells ),
"Can't add polygonal entities" );
assert( dualcells.
size() == verts.
size() );
gids.resize( verts.
size() );
MB_CHK_SET_ERR(
mb->tag_get_data( gidTag, verts, &gids[0] ),
"Can't set global_id tag" );
if( gids[0] == gids[1] && gids[0] < 0 )
{
#ifdef MOAB_HAVE_MPI
#else
for( size_t ix = 0; ix < gids.size(); ++ix )
gids[ix] = ix + 1;
MB_CHK_SET_ERR(
mb->tag_set_data( gidTag, dualcells, &gids[0] ),
"Can't set global_id tag" );
std::cout << "GIDs: " << gids[0] << " " << gids[1] << " " << gids[2] << " " << gids[3] << " " << gids[4] << " "
<< gids[5] << "\n";
#endif
}
gids.clear();
}
int main(
int argc,
char** argv )
{
if( NULL ==
mb )
return 1;
std::string inputFile = std::string(
MESH_DIR ) +
"/globalmpas_deltri.h5m";
opts.
addOpt< std::string >(
"inFile,i",
"Specify the input file name string ", &inputFile );
#ifdef MOAB_HAVE_HDF5
std::string outputFile = "outDualMesh.h5m";
#else
std::string outputFile = "outDualMesh.vtk";
#endif
opts.
addOpt< std::string >(
"outFile,o",
"Specify the input file name string ", &outputFile );
const char* readopts = "";
MB_CHK_SET_ERR(
mb->load_file( inputFile.c_str(), &triangle_set, readopts ),
"Failed to read" );
MB_CHK_SET_ERR(
mb->get_entities_by_dimension( triangle_set, 2, cells ),
"Failed to get cells" );
std::cout <<
"Original number of triangular cells : " << cells.
size() <<
"\n";
MB_CHK_SET_ERR(
mb->write_file( outputFile.c_str() ),
"Failed to write new file" );
MB_CHK_SET_ERR(
mb->get_entities_by_dimension( dual_set, 2, cells ),
"Failed to get cells" );
std::cout <<
"Wrote the dual mesh: " << outputFile <<
" containing " << cells.
size() <<
" polygonal cells\n";
return 0;
}