Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
DirectAccessWithHoles.cpp File Reference

Example demonstrating direct access to MOAB data with holes in entity handle space. More...

#include "moab/Core.hpp"
#include "moab/ProgOptions.hpp"
#include "moab/ReadUtilIface.hpp"
#include <map>
#include <iostream>
#include <cassert>
+ Include dependency graph for DirectAccessWithHoles.cpp:

Go to the source code of this file.

Classes

struct  tag_struct
 

Functions

ErrorCode create_mesh_with_holes (Interface *mbImpl, int nquads, int nholes)
 
int main (int argc, char **argv)
 

Detailed Description

Example demonstrating direct access to MOAB data with holes in entity handle space.

This example shows how to:

  • Create a structured mesh with holes in the entity handle space
  • Use direct access iterators to avoid API overhead
  • Handle non-contiguous entity handles efficiently
  • Access vertex coordinates, element connectivity, and tag data directly
  • Work with adjacency lists for vertex-to-element relationships
  • Use maps to track data chunks for non-contiguous handles

The program creates a 1D row of quad elements with specified holes, then demonstrates direct access to MOAB's internal data structures even when entity handles are not contiguous.

Author
MOAB Development Team
Date
2024

Use direct access to MOAB data to avoid calling through API
This example creates a 1d row of quad elements, with a user-specified number of "holes" (missing quads) in the row:

*  ----------------------      ----------------------      --------
*  |      |      |      |      |      |      |      |      |      |
*  |      |      |      |(hole)|      |      |      |(hole)|      | ...
*  |      |      |      |      |      |      |      |      |      |
*  ----------------------      ----------------------      --------
* 

This makes (nholes+1) contiguous runs of quad handles in the handle space This example shows how to use the xxx_iterate functions in MOAB (xxx = coords, connect, tag, adjacencies) to get direct pointer access to MOAB internal storage, which can be used without calling through the MOAB API.

  1. Initialize MOAB
  2. Create a quad mesh with holes, as depicted above
  3. Create 2 dense tags (tag1, tag2) for avg position to assign to quads, and # verts per quad (tag3)
  4. Get connectivity, coordinate, tag1 iterators
  5. Iterate through quads, computing midpoint based on vertex positions, set on quad-based tag1
  6. Set up map from starting quad handle for a chunk to struct of (tag1_ptr, tag2_ptr, tag3_ptr), pointers to the dense tag storage for those tags for the chunk
  7. Iterate through vertices, summing positions into tag2 on connected quads and incrementing vertex count
  8. Iterate through quads, normalizing tag2 by vertex count and comparing values of tag1 and tag2

To compile:
make DirectAccessWithHoles
To run: ./DirectAccess [-nquads <# quads>] [-holes <# holes>]

Parameters
argcNumber of command line arguments
argvCommand line arguments array
Returns
0 on success, 1 on failure

Definition in file DirectAccessWithHoles.cpp.

Function Documentation

◆ create_mesh_with_holes()

ErrorCode create_mesh_with_holes ( Interface mbImpl,
int  nquads,
int  nholes 
)

Definition at line 266 of file DirectAccessWithHoles.cpp.

267 {
268  // First make the mesh, a 1d array of quads with left hand side x = elem_num; vertices are
269  // numbered in layers
270  ReadUtilIface* read_iface;
271  MB_CHK_SET_ERR( mbImpl->query_interface( read_iface ), "Error in query_interface" );
272  vector< double* > coords;
273  EntityHandle start_vert, start_elem, *connect;
274  // Create verts, num is 4(nquads+1) because they're in a 1d row; will initialize coords in loop
275  // over elems later
276  MB_CHK_SET_ERR( read_iface->get_node_coords( 3, 2 * ( nquads + 1 ), 0, start_vert, coords ),
277  "Error in get_node_arrays" );
278  // Create elems
279  MB_CHK_SET_ERR( read_iface->get_element_connect( nquads, 4, MBQUAD, 0, start_elem, connect ),
280  "Error in get_element_connect" );
281  for( int i = 0; i < nquads; i++ )
282  {
283  coords[0][2 * i] = coords[0][2 * i + 1] = (double)i; // x values are all i
284  coords[1][2 * i] = 0.0;
285  coords[1][2 * i + 1] = 1.0; // y coords
286  coords[2][2 * i] = coords[2][2 * i + 1] = (double)0.0; // z values, all zero (2d mesh)
287  EntityHandle quad_v = start_vert + 2 * i;
288  for( int j = 0; j < 4; j++ )
289  connect[4 * i + j] = quad_v + j; // Connectivity of each quad is a sequence starting from quad_v
290  }
291  // Last two vertices
292  // Cppcheck warning (false positive): variable coords is assigned a value that is never used
293  coords[0][2 * nquads] = coords[0][2 * nquads + 1] = (double)nquads;
294  coords[1][2 * nquads] = 0.0;
295  coords[1][2 * nquads + 1] = 1.0; // y coords
296  coords[2][2 * nquads] = coords[2][2 * nquads + 1] = (double)0.0; // z values, all zero (2d mesh)
297 
298  // Now delete nholes elements, spaced approximately equally through mesh, so contiguous size is
299  // about nquads/(nholes + 1) reinterpret start_elem as the next element to be deleted
300  int de = nquads / ( nholes + 1 );
301  for( int i = 0; i < nholes; i++ )
302  {
303  start_elem += de;
304  MB_CHK_SET_ERR( mbImpl->delete_entities( &start_elem, 1 ), "Error in delete_entities" );
305  }
306 
307  return MB_SUCCESS;
308 }

References moab::Interface::delete_entities(), moab::ReadUtilIface::get_element_connect(), moab::ReadUtilIface::get_node_coords(), MB_CHK_SET_ERR, MB_SUCCESS, MBQUAD, and moab::Interface::query_interface().

Referenced by main().

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 77 of file DirectAccessWithHoles.cpp.

78 {
79  // Get MOAB instance
80  Interface* mbImpl = new( std::nothrow ) Core;
81  if( NULL == mbImpl ) return 1;
82 
83  int nquads = 1000, nholes = 1;
84 
85  // Parse options
86  ProgOptions opts;
87  opts.addOpt< int >( string( "nquads,n" ), string( "Number of quads in the mesh (default = 1000" ), &nquads );
88  opts.addOpt< int >( string( "holes,H" ), string( "Number of holes in the element handle space (default = 1" ),
89  &nholes );
90  opts.parseCommandLine( argc, argv );
91  if( nholes >= nquads )
92  {
93  cerr << "Number of holes needs to be < number of elements." << endl;
94  return 1;
95  }
96 
97  // Create simple structured mesh with hole, but using unstructured representation
98  MB_CHK_SET_ERR( create_mesh_with_holes( mbImpl, nquads, nholes ), "Trouble creating mesh" );
99 
100  // Get all vertices and non-vertex entities
101  Range verts, elems;
102  MB_CHK_SET_ERR( mbImpl->get_entities_by_handle( 0, elems ), "Trouble getting all entities" );
103  verts = elems.subset_by_dimension( 0 );
104  elems -= verts;
105 
106  // Create tag1 (element-based avg), tag2 (vertex-based avg), tag3 (# connected verts)
107  Tag tag1, tag2, tag3;
108  MB_CHK_SET_ERR( mbImpl->tag_get_handle( "tag1", 3, MB_TYPE_DOUBLE, tag1, MB_TAG_DENSE | MB_TAG_CREAT ),
109  "Trouble creating tag1" );
110  double def_val[3] = { 0.0, 0.0, 0.0 }; // Need a default value for tag2 because we sum into it
111  MB_CHK_SET_ERR( mbImpl->tag_get_handle( "tag2", 3, MB_TYPE_DOUBLE, tag2, MB_TAG_DENSE | MB_TAG_CREAT, def_val ),
112  "Trouble creating tag2" );
113  int def_val_int = 0; // Need a default value for tag3 because we increment it
115  &def_val_int ),
116  "Trouble creating tag3" );
117 
118  // Get connectivity, coordinate, tag, and adjacency iterators
119  EntityHandle* conn_ptr;
120  double *x_ptr, *y_ptr, *z_ptr, *tag1_ptr, *tag2_ptr;
121  int* tag3_ptr;
122 
123  // First vertex is at start of range (ranges are sorted), and is offset for vertex index
124  // calculation
125  EntityHandle first_vert = *verts.begin();
126 
127  // When iterating over elements, each chunk can have a different # vertices; also, count tells
128  // you how many elements are in the current chunk
129  int vpere, count;
130 
131  // Get coordinates iterator, just need this once because we know verts handle space doesn't have
132  // holes
133  MB_CHK_SET_ERR( mbImpl->coords_iterate( verts.begin(), verts.end(), x_ptr, y_ptr, z_ptr, count ),
134  "Error in coords_iterate" );
135  assert( count == (int)verts.size() ); // Should end up with just one contiguous chunk of vertices
136 
137  // Iterate through elements, computing midpoint based on vertex positions, set on element-based
138  // tag1 Control loop by iterator over elem range
139  Range::iterator e_it = elems.begin();
140 
141  while( e_it != elems.end() )
142  {
143  // Get conn_ptr, tag1_ptr for next contiguous chunk of element handles, and coords pointers
144  // for all verts
145  MB_CHK_SET_ERR( mbImpl->connect_iterate( e_it, elems.end(), conn_ptr, vpere, count ),
146  "Error in connect_iterate" );
147  MB_CHK_SET_ERR( mbImpl->tag_iterate( tag1, e_it, elems.end(), count, (void*&)tag1_ptr ),
148  "Error in tag1_iterate" );
149 
150  // Iterate over elements in this chunk
151  for( int i = 0; i < count; i++ )
152  {
153  tag1_ptr[0] = tag1_ptr[1] = tag1_ptr[2] = 0.0; // Initialize position for this element
154  for( int j = 0; j < vpere; j++ )
155  { // Loop over vertices in this element
156  int v_index = conn_ptr[j] - first_vert; // vert index is just the offset from first vertex
157  tag1_ptr[0] += x_ptr[v_index];
158  tag1_ptr[1] += y_ptr[v_index]; // Sum vertex positions into tag1...
159  tag1_ptr[2] += z_ptr[v_index];
160  }
161  tag1_ptr[0] /= vpere;
162  tag1_ptr[1] /= vpere; // Then normalize
163  tag1_ptr[2] /= vpere;
164 
165  // Done with this element; advance connect_ptr and tag1_ptr to next element
166  conn_ptr += vpere;
167  tag1_ptr += 3;
168  } // Loop over elements in chunk
169 
170  // Done with chunk; advance range iterator by count; will skip over gaps in range
171  e_it += count;
172  } // While loop over all elements
173 
174  // Iterate through vertices, summing positions into tag2 on connected elements and incrementing
175  // vertex count Iterate over chunks the same as elements, even though we know we have only one
176  // chunk here, just to show how it's done
177 
178  // Create a std::map from EntityHandle (first entity handle in chunk) to
179  // tag_struct (ptrs to start of avg/#verts tags for that chunk); then for a given entity handle,
180  // we can quickly find the chunk it's in using map::lower_bound; could have set up this map in
181  // earlier loop over elements, but do it here for clarity
182 
183  map< EntityHandle, tag_struct > elem_map;
184  e_it = elems.begin();
185  while( e_it != elems.end() )
186  {
187  tag_struct ts = { NULL, NULL };
188  MB_CHK_SET_ERR( mbImpl->tag_iterate( tag2, e_it, elems.end(), count, (void*&)ts.avg_ptr ),
189  "Error in tag2_iterate" );
190  MB_CHK_SET_ERR( mbImpl->tag_iterate( tag3, e_it, elems.end(), count, (void*&)ts.nv_ptr ),
191  "Error in tag3_iterate" );
192  elem_map[*e_it] = ts;
193  e_it += count;
194  }
195 
196  // Call a vertex-quad adjacencies function to generate vertex-element adjacencies in MOAB
197  Range::iterator v_it = verts.begin();
198  Range dum_range;
199  MB_CHK_SET_ERR( mbImpl->get_adjacencies( &( *v_it ), 1, 2, false, dum_range ), "Error in get_adjacencies" );
200  const vector< EntityHandle >** adjs_ptr;
201  while( v_it != verts.end() )
202  {
203  // Get coords ptrs, adjs_ptr; can't set tag2_ptr by direct access, because of hole in
204  // element handle space
205  MB_CHK_SET_ERR( mbImpl->coords_iterate( v_it, verts.end(), x_ptr, y_ptr, z_ptr, count ),
206  "Error in coords_iterate" );
207  MB_CHK_SET_ERR( mbImpl->adjacencies_iterate( v_it, verts.end(), adjs_ptr, count ),
208  "Error in adjacencies_iterate" );
209 
210  for( int v = 0; v < count; v++ )
211  {
212  const vector< EntityHandle >* avec = *( adjs_ptr + v );
213  for( vector< EntityHandle >::const_iterator ait = avec->begin(); ait != avec->end(); ++ait )
214  {
215  // Get chunk that this element resides in; upper_bound points to the first element
216  // strictly > key, so get that and decrement (would work the same as lower_bound
217  // with an if-test and decrement)
218  map< EntityHandle, tag_struct >::iterator mit = elem_map.upper_bound( *ait );
219  --mit;
220  // Index of *ait in that chunk
221  int a_ind = *ait - ( *mit ).first;
222  tag_struct ts = ( *mit ).second;
223  ts.avg_ptr[3 * a_ind + 0] += x_ptr[v]; // Tag on each element is 3 doubles, x/y/z
224  ts.avg_ptr[3 * a_ind + 1] += y_ptr[v];
225  ts.avg_ptr[3 * a_ind + 2] += z_ptr[v];
226  ts.nv_ptr[a_ind]++; // Increment the vertex count
227  }
228  }
229 
230  v_it += count;
231  }
232 
233  // Normalize tag2 by vertex count; loop over elements using same approach as before
234  // At the same time, compare values of tag1 and tag2
235  e_it = elems.begin();
236  while( e_it != elems.end() )
237  {
238  // Get conn_ptr, tag1_ptr for next contiguous chunk of element handles, and coords pointers
239  // for all verts
240  MB_CHK_SET_ERR( mbImpl->tag_iterate( tag1, e_it, elems.end(), count, (void*&)tag1_ptr ),
241  "Error in tag1_iterate" );
242  MB_CHK_SET_ERR( mbImpl->tag_iterate( tag2, e_it, elems.end(), count, (void*&)tag2_ptr ),
243  "Error in tag2_iterate" );
244  MB_CHK_SET_ERR( mbImpl->tag_iterate( tag3, e_it, elems.end(), count, (void*&)tag3_ptr ),
245  "Error in tag3_iterate" );
246 
247  // Iterate over elements in this chunk
248  for( int i = 0; i < count; i++ )
249  {
250  for( int j = 0; j < 3; j++ )
251  tag2_ptr[3 * i + j] /= (double)tag3_ptr[i]; // Normalize by # verts
252  if( tag1_ptr[3 * i] != tag2_ptr[3 * i] || tag1_ptr[3 * i + 1] != tag2_ptr[3 * i + 1] ||
253  tag1_ptr[3 * i + 2] != tag2_ptr[3 * i + 2] )
254  cout << "Tag1, tag2 disagree for element " << *e_it + i << endl;
255  }
256 
257  e_it += count;
258  }
259 
260  // Ok, we're done, shut down MOAB
261  delete mbImpl;
262 
263  return 0;
264 }

References ProgOptions::addOpt(), moab::Interface::adjacencies_iterate(), tag_struct::avg_ptr, moab::Range::begin(), moab::Interface::connect_iterate(), moab::Interface::coords_iterate(), create_mesh_with_holes(), moab::Range::end(), moab::Interface::get_adjacencies(), moab::Interface::get_entities_by_handle(), MB_CHK_SET_ERR, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_DOUBLE, MB_TYPE_INTEGER, tag_struct::nv_ptr, ProgOptions::parseCommandLine(), moab::Range::size(), moab::Range::subset_by_dimension(), moab::Interface::tag_get_handle(), and moab::Interface::tag_iterate().