Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
ComputeTriDual.cpp
Go to the documentation of this file.
1 /** @example ComputeTriDual.cpp
2  * This example demonstrates computation of dual polygonal mesh from primal triangulation.
3  * It shows how to load a triangular mesh from a file,
4  * compute the dual polygonal mesh of a triangulation,
5  * handle spherical surface triangulations,
6  * create dual vertices at triangle centroids,
7  * generate dual polygons around primal vertices,
8  * orient dual polygons correctly on spherical surfaces,
9  * preserve global IDs during dual mesh construction,
10  * and write the dual mesh to a new file.
11  *
12  * The dual mesh computation is particularly useful for finite volume
13  * methods and other applications requiring dual grid structures.
14  *
15  * To run: ComputeTriDual input_file output_file
16  * An example to demonstrate computing the dual polygonal grid of a triangulation
17  * on a spherical surface.
18  */
19 
20 #include <iostream>
21 #include <vector>
22 
23 // Include header for MOAB instance and tag conventions for
24 #include "moab/Interface.hpp"
25 #include "moab/Range.hpp"
26 #include "moab/ProgOptions.hpp"
27 #include "moab/CartVect.hpp"
28 #include "moab/Core.hpp"
29 #include "moab/ReadUtilIface.hpp"
30 
31 #ifdef MOAB_HAVE_MPI
32 #include "moab/ParallelComm.hpp"
33 #endif
34 
35 ///////////////////////////////////////////////////////////////////////////////
36 
38 {
39  moab::ErrorCode rval;
40 
41  moab::Range verts;
42  MB_CHK_SET_ERR( mb->get_connectivity( cells, verts ), "Failed to get connectivity" );
43 
45  MB_CHK_SET_ERR( mb->query_interface( iface ), "Can't get reader interface" );
46 
47  moab::EntityHandle startv;
48  std::vector< double* > ccenters;
49  MB_CHK_SET_ERR( iface->get_node_coords( 3, cells.size(), 0, startv, ccenters ), "Can't get node coords" );
50 
51  moab::Tag gidTag = mb->globalId_tag();
52 
53  std::vector< int > gids( cells.size() );
54  MB_CHK_SET_ERR( mb->get_coords( cells, ccenters[0], ccenters[1], ccenters[2] ), "Failed to get coordinates" );
55  MB_CHK_SET_ERR( mb->tag_get_data( gidTag, cells, &gids[0] ), "Can't set global_id tag" );
56 
57  moab::Range dualverts( startv, startv + cells.size() - 1 );
58  MB_CHK_SET_ERR( mb->add_entities( dual_set, dualverts ), "Can't add entities" );
59  MB_CHK_SET_ERR( mb->tag_set_data( gidTag, dualverts, &gids[0] ), "Can't set global_id tag" );
60 
61 #define CC( ind ) moab::CartVect( ccenters[0][ind], ccenters[1][ind], ccenters[2][ind] )
62 #define CCXMY( ind, cv ) \
63  moab::CartVect( ccenters[0][ind] - ( cv )[0], ccenters[1][ind] - ( cv )[1], ccenters[2][ind] - ( cv )[2] )
64 
65  const moab::EntityHandle svtx = *( cells.begin() );
66 
67  // maintain block-wise polygon elements
68  moab::Range dualcells;
69  std::map< size_t, std::vector< moab::EntityHandle > > polygonConn;
70  // Generate new Face array
71  for( moab::Range::iterator vit = verts.begin(); vit != verts.end(); ++vit )
72  {
73  moab::EntityHandle vtx = *vit;
74 
75  std::vector< moab::EntityHandle > adjs;
76  // generate all required adjacencies
77  MB_CHK_SET_ERR( mb->get_adjacencies( &vtx, 1, 2, true, adjs ), "Failed to get adjacencies" );
78  const size_t nEdges = adjs.size();
79 
80  double vxyz[3];
81  MB_CHK_SET_ERR( mb->get_coords( &vtx, 1, vxyz ), "Failed to get coordinates" );
82 
83  // Reorient Faces
84  moab::CartVect nodeCentral( vxyz );
85  moab::CartVect noderef = CC( adjs[0] - svtx );
86  moab::CartVect node0 = noderef - nodeCentral;
87  double dNode0Mag = node0.length();
88 
89  moab::CartVect nodeCross = noderef * nodeCentral;
90 
91  // Determine the angles about the central Node of each Face Node
92  std::vector< double > dAngles;
93  dAngles.resize( nEdges );
94  dAngles[0] = 0.0;
95 
96  for( size_t j = 1; j < nEdges; j++ )
97  {
98  moab::CartVect nodeDiff = CCXMY( adjs[j] - svtx, nodeCentral );
99  double dNodeDiffMag = nodeDiff.length();
100 
101  double dSide = nodeCross % nodeDiff;
102  double dDotNorm = ( node0 % nodeDiff ) / ( dNode0Mag * dNodeDiffMag );
103 
104  // double dAngle;
105  if( dDotNorm > 1.0 )
106  {
107  dDotNorm = 1.0;
108  }
109 
110  dAngles[j] = acos( dDotNorm );
111 
112  if( dSide > 0.0 )
113  {
114  dAngles[j] = -dAngles[j] + 2.0 * M_PI;
115  }
116  }
117 
118  std::vector< moab::EntityHandle >& face = polygonConn[nEdges];
119  if( face.size() == 0 ) face.reserve( nEdges * verts.size() / 4 );
120  face.push_back( dualverts[adjs[0] - svtx] );
121 
122  // Orient each Face by putting Nodes in order of increasing angle
123  double dCurrentAngle = 0.0;
124  for( size_t j = 1; j < nEdges; j++ )
125  {
126  int ixNextNode = 1;
127  double dNextAngle = 2.0 * M_PI;
128 
129  for( size_t k = 1; k < nEdges; k++ )
130  {
131  if( ( dAngles[k] > dCurrentAngle ) && ( dAngles[k] < dNextAngle ) )
132  {
133  ixNextNode = k;
134  dNextAngle = dAngles[k];
135  }
136  }
137 
138  face.push_back( dualverts[adjs[ixNextNode] - svtx] );
139  dCurrentAngle = dNextAngle;
140  }
141  }
142 
143  std::map< size_t, std::vector< moab::EntityHandle > >::iterator eit;
144  for( eit = polygonConn.begin(); eit != polygonConn.end(); ++eit )
145  {
146  const size_t nVPerE = eit->first;
147  const size_t nElePerType = static_cast< int >( eit->second.size() / nVPerE );
148 
149  moab::EntityHandle starte; // Connectivity
150  moab::EntityHandle* conn;
151 
152  MB_CHK_SET_ERR( iface->get_element_connect( nElePerType, eit->first, moab::MBPOLYGON, 0, starte, conn ),
153  "Can't get element connectivity" );
154 
155  // copy the connectivity that we have accumulated
156  std::copy( eit->second.begin(), eit->second.end(), conn );
157  eit->second.clear();
158 
159  // add this polygon sequence to the aggregate data
160  moab::Range mbcells( starte, starte + nElePerType - 1 );
161  dualcells.merge( mbcells );
162  }
163 
164  // add the computed dual cells to mesh
165  MB_CHK_SET_ERR( mb->add_entities( dual_set, dualcells ), "Can't add polygonal entities" );
166 
167  // Assign global IDs to all the dual cells - same as original vertices
168  assert( dualcells.size() == verts.size() );
169  gids.resize( verts.size() );
170  MB_CHK_SET_ERR( mb->tag_get_data( gidTag, verts, &gids[0] ), "Can't set global_id tag" );
171  if( gids[0] == gids[1] && gids[0] < 0 )
172  {
173 #ifdef MOAB_HAVE_MPI
174  moab::ParallelComm pcomm( mb, MPI_COMM_WORLD );
175 
176  MB_CHK_SET_ERR( pcomm.assign_global_ids( dual_set, 2, 1, false, true, true ), "Can't assign global_ids" );
177 #else
178  // No global ID assigned to input vertices.
179  // Can we use std::iota ??
180  for( size_t ix = 0; ix < gids.size(); ++ix )
181  gids[ix] = ix + 1;
182 
183  // set GID tag
184  MB_CHK_SET_ERR( mb->tag_set_data( gidTag, dualcells, &gids[0] ), "Can't set global_id tag" );
185  std::cout << "GIDs: " << gids[0] << " " << gids[1] << " " << gids[2] << " " << gids[3] << " " << gids[4] << " "
186  << gids[5] << "\n";
187 #endif
188  }
189  gids.clear();
190 
191  // delete the original entities from the mesh
192  MB_CHK_SET_ERR( mb->delete_entities( cells ), "Can't remove entities" );
193  MB_CHK_SET_ERR( mb->delete_entities( verts ), "Can't remove entities" );
194 
195  return moab::MB_SUCCESS;
196 }
197 
198 ///////////////////////////////////////////////////////////////////////////////
199 
200 int main( int argc, char** argv )
201 {
202  moab::ErrorCode rval;
203  ProgOptions opts;
204 
205  // Get MOAB instance
206  moab::Interface* mb = new( std::nothrow ) moab::Core;
207  if( NULL == mb ) return 1;
208 
209  std::string inputFile = std::string( MESH_DIR ) + "/globalmpas_deltri.h5m";
210  opts.addOpt< std::string >( "inFile,i", "Specify the input file name string ", &inputFile );
211 #ifdef MOAB_HAVE_HDF5
212  std::string outputFile = "outDualMesh.h5m";
213 #else
214  std::string outputFile = "outDualMesh.vtk";
215 #endif
216  opts.addOpt< std::string >( "outFile,o", "Specify the input file name string ", &outputFile );
217 
218  opts.parseCommandLine( argc, argv );
219 
220  moab::EntityHandle triangle_set, dual_set;
221  MB_CHK_SET_ERR( mb->create_meshset( moab::MESHSET_SET, triangle_set ), "Can't create new set" );
222  MB_CHK_SET_ERR( mb->create_meshset( moab::MESHSET_SET, dual_set ), "Can't create new set" );
223 
224  // This file is in the mesh files directory
225  const char* readopts = "";
226  MB_CHK_SET_ERR( mb->load_file( inputFile.c_str(), &triangle_set, readopts ), "Failed to read" );
227 
228  // get all cells of dimension 2;
229  moab::Range cells;
230  MB_CHK_SET_ERR( mb->get_entities_by_dimension( triangle_set, 2, cells ), "Failed to get cells" );
231 
232  std::cout << "Original number of triangular cells : " << cells.size() << "\n";
233 
234  // call the routine to compute the dual grid
235  MB_CHK_SET_ERR( compute_dual_mesh( mb, dual_set, cells ), "Failed to compute dual mesh" );
236 
237  // write the mesh to disk
238  MB_CHK_SET_ERR( mb->write_file( outputFile.c_str() ), "Failed to write new file" );
239 
240  cells.clear();
241  MB_CHK_SET_ERR( mb->get_entities_by_dimension( dual_set, 2, cells ), "Failed to get cells" );
242  std::cout << "Wrote the dual mesh: " << outputFile << " containing " << cells.size() << " polygonal cells\n";
243 
244  delete mb;
245 
246  return 0;
247 }