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

Example demonstrating direct access to MOAB data for performance optimization. More...

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

Go to the source code of this file.

Functions

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

Detailed Description

Example demonstrating direct access to MOAB data for performance optimization.

This example shows how to:

  • Create a structured mesh with contiguous entity handles
  • Use direct access iterators to avoid API overhead
  • Access vertex coordinates, element connectivity, and tag data directly
  • Work with adjacency lists for vertex-to-element relationships
  • Perform efficient mesh operations using pointer arithmetic

The program creates a 1D row of quad elements with contiguous handles, then demonstrates direct access to MOAB's internal data structures for maximum performance when the mesh topology is static.

Author
MOAB Team
Date
2024
Parameters
[in]argcNumber of command line arguments
[in]argvCommand line arguments array
[in]-nquadsNumber of quads in the mesh (default: 1000)
Returns
0 on success, 1 on failure
Usage:
./DirectAccessNoHoles [-nquads <# quads>]
Example:
./DirectAccessNoHoles -nquads 500
See also
Core, Interface, ReadUtilIface, ProgOptions

Use direct access to MOAB data to avoid calling through API
This example creates a 1d row of quad elements, such that all quad and vertex handles are contiguous in the handle space and in the database. Then it shows how to get access to pointers to MOAB-native data for vertex coordinates, quad connectivity, tag storage, and vertex to quad adjacency lists. This allows applications to access this data directly without going through MOAB's API. In cases where the mesh is not changing (or only mesh vertices are moving), this can save significant execution time in applications.

*  ----------------------
*  |      |      |      |
*  |      |      |      | ...
*  |      |      |      |
*  ----------------------
* 
  1. Initialize MOAB
  2. Create a quad mesh, 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. Iterate through vertices, summing positions into tag2 on connected quads and incrementing vertex count
  7. Iterate through quads, normalizing tag2 by vertex count and comparing values of tag1 and tag2

To compile:
make DirectAccessNoHoles
To run: ./DirectAccessNoHoles [-nquads <# quads>]

Definition in file DirectAccessNoHoles.cpp.

Function Documentation

◆ create_mesh_no_holes()

ErrorCode create_mesh_no_holes ( Interface mbImpl,
int  nquads 
)

Definition at line 206 of file DirectAccessNoHoles.cpp.

207 {
208  // First make the mesh, a 1d array of quads with left hand side x = elem_num; vertices are
209  // numbered in layers
210  ReadUtilIface* read_iface;
211  MB_CHK_SET_ERR( mbImpl->query_interface( read_iface ), "Error in query_interface" );
212  vector< double* > coords;
213  EntityHandle start_vert, start_elem, *connect;
214  // Create verts, num is 2(nquads+1) because they're in a 1d row; will initialize coords in loop
215  // over quads later
216  MB_CHK_SET_ERR( read_iface->get_node_coords( 3, 2 * ( nquads + 1 ), 0, start_vert, coords ),
217  "Error in get_node_arrays" );
218  // Create quads
219  MB_CHK_SET_ERR( read_iface->get_element_connect( nquads, 4, MBQUAD, 0, start_elem, connect ),
220  "Error in get_element_connect" );
221  for( int i = 0; i < nquads; i++ )
222  {
223  coords[0][2 * i] = coords[0][2 * i + 1] = (double)i; // x values are all i
224  coords[1][2 * i] = 0.0;
225  coords[1][2 * i + 1] = 1.0; // y coords
226  coords[2][2 * i] = coords[2][2 * i + 1] = (double)0.0; // z values, all zero (2d mesh)
227  EntityHandle quad_v = start_vert + 2 * i;
228  connect[4 * i + 0] = quad_v;
229  connect[4 * i + 1] = quad_v + 2;
230  connect[4 * i + 2] = quad_v + 3;
231  connect[4 * i + 3] = quad_v + 1;
232  }
233 
234  // Last two vertices
235  // Cppcheck warning (false positive): variable coords is assigned a value that is never used
236  coords[0][2 * nquads] = coords[0][2 * nquads + 1] = (double)nquads;
237  coords[1][2 * nquads] = 0.0;
238  coords[1][2 * nquads + 1] = 1.0; // y coords
239  coords[2][2 * nquads] = coords[2][2 * nquads + 1] = (double)0.0; // z values, all zero (2d mesh)
240 
241  // Call a vertex-quad adjacencies function to generate vertex-element adjacencies in MOAB
242  Range dum_range;
243  MB_CHK_SET_ERR( mbImpl->get_adjacencies( &start_vert, 1, 2, false, dum_range ), "Error in get_adjacencies" );
244  assert( !dum_range.empty() );
245 
246  return MB_SUCCESS;
247 }

References moab::Range::empty(), moab::Interface::get_adjacencies(), 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 83 of file DirectAccessNoHoles.cpp.

84 {
85  // Get MOAB instance
86  Interface* mbImpl = new( std::nothrow ) Core;
87  if( NULL == mbImpl ) return 1;
88 
89  int nquads = 1000;
90 
91  // Parse options
92  ProgOptions opts;
93  opts.addOpt< int >( string( "nquads,n" ), string( "Number of quads in the mesh (default = 1000" ), &nquads );
94  opts.parseCommandLine( argc, argv );
95 
96  // Create simple structured mesh with hole, but using unstructured representation
97  MB_CHK_SET_ERR( create_mesh_no_holes( mbImpl, nquads ), "Trouble creating mesh" );
98 
99  // Get all vertices and non-vertex entities
100  Range verts, quads;
101  MB_CHK_SET_ERR( mbImpl->get_entities_by_handle( 0, quads ), "Trouble getting all entities" );
102  verts = quads.subset_by_dimension( 0 );
103  quads -= verts;
104 
105  // Create tag1 (element-based avg), tag2 (vertex-based avg), tag3 (# connected verts)
106  Tag tag1, tag2, tag3;
107  MB_CHK_SET_ERR( mbImpl->tag_get_handle( "tag1", 3, MB_TYPE_DOUBLE, tag1, MB_TAG_DENSE | MB_TAG_CREAT ),
108  "Trouble creating tag1" );
109  double def_val[3] = { 0.0, 0.0, 0.0 }; // need a default value for tag2 because we sum into it
110  MB_CHK_SET_ERR( mbImpl->tag_get_handle( "tag2", 3, MB_TYPE_DOUBLE, tag2, MB_TAG_DENSE | MB_TAG_CREAT, def_val ),
111  "Trouble creating tag2" );
112  int def_val_int = 0; // need a default value for tag3 because we increment it
114  &def_val_int ),
115  "Trouble creating tag3" );
116 
117  // Get pointers to connectivity, coordinate, tag, and adjacency arrays; each of these returns a
118  // count, which should be compared to the # entities you expect to verify there's only one chunk
119  // (no holes)
120  int count, vpere;
121  EntityHandle* conn_ptr;
122  MB_CHK_SET_ERR( mbImpl->connect_iterate( quads.begin(), quads.end(), conn_ptr, vpere, count ),
123  "Error in connect_iterate" );
124  assert( count == (int)quads.size() ); // Should end up with just one contiguous chunk of quads
125 
126  double *x_ptr, *y_ptr, *z_ptr;
127  MB_CHK_SET_ERR( mbImpl->coords_iterate( verts.begin(), verts.end(), x_ptr, y_ptr, z_ptr, count ),
128  "Error in coords_iterate" );
129  assert( count == (int)verts.size() ); // Should end up with just one contiguous chunk of vertices
130 
131  double *tag1_ptr, *tag2_ptr;
132  int* tag3_ptr;
133  MB_CHK_SET_ERR( mbImpl->tag_iterate( tag1, quads.begin(), quads.end(), count, (void*&)tag1_ptr ),
134  "Error in tag1_iterate" );
135  assert( count == (int)quads.size() ); // Should end up with just one contiguous chunk of quads
136  MB_CHK_SET_ERR( mbImpl->tag_iterate( tag2, quads.begin(), quads.end(), count, (void*&)tag2_ptr ),
137  "Error in tag2_iterate" );
138  assert( count == (int)quads.size() ); // Should end up with just one contiguous chunk of quads
139  MB_CHK_SET_ERR( mbImpl->tag_iterate( tag3, quads.begin(), quads.end(), count, (void*&)tag3_ptr ),
140  "Error in tag3_iterate" );
141  assert( count == (int)quads.size() ); // Should end up with just one contiguous chunk of quads
142 
143  const vector< EntityHandle >** adjs_ptr;
144  MB_CHK_SET_ERR( mbImpl->adjacencies_iterate( verts.begin(), verts.end(), adjs_ptr, count ),
145  "Error in adjacencies_iterate" );
146  assert( count == (int)verts.size() ); // Should end up with just one contiguous chunk of vertices
147  // Start_ handles used to compute indices into vertex/quad arrays; can use direct subtraction
148  // because we know there aren't any holes in the handle spaces for verts or quads
149  EntityHandle start_vert = *verts.begin(), start_quad = *quads.begin();
150 
151  // Iterate over elements, computing tag1 from coords positions
152  for( int i = 0; i < nquads; i++ )
153  {
154  tag1_ptr[3 * i + 0] = tag1_ptr[3 * i + 1] = tag1_ptr[3 * i + 2] = 0.0; // Initialize position for this element
155  for( int j = 0; j < vpere; j++ )
156  { // Loop over vertices in this element
157  int v_index = conn_ptr[vpere * i + j] - start_vert; // vert index is just the offset from start vertex
158  tag1_ptr[3 * i + 0] += x_ptr[v_index];
159  tag1_ptr[3 * i + 1] += y_ptr[v_index]; // Sum vertex positions into tag1...
160  tag1_ptr[3 * i + 2] += z_ptr[v_index];
161  }
162  tag1_ptr[3 * i + 0] /= vpere;
163  tag1_ptr[3 * i + 1] /= vpere; // Then normalize
164  tag1_ptr[3 * i + 2] /= vpere;
165  } // Loop over elements in chunk
166 
167  // Iterate through vertices, summing positions into tag2 on connected elements and incrementing
168  // vertex count
169  for( int v = 0; v < count; v++ )
170  {
171  const vector< EntityHandle >* avec = *( adjs_ptr + v );
172  for( vector< EntityHandle >::const_iterator ait = avec->begin(); ait != avec->end(); ++ait )
173  {
174  // *ait is the quad handle, its index is computed by subtracting the start quad handle
175  int a_ind = *ait - start_quad;
176  tag2_ptr[3 * a_ind + 0] += x_ptr[v]; // Tag on each element is 3 doubles, x/y/z
177  tag2_ptr[3 * a_ind + 1] += y_ptr[v];
178  tag2_ptr[3 * a_ind + 2] += z_ptr[v];
179  tag3_ptr[a_ind]++; // Increment the vertex count
180  }
181  }
182 
183  // Normalize tag2 by vertex count (tag3); loop over elements using same approach as before
184  // At the same time, compare values of tag1 and tag2
185  int n_dis = 0;
186  for( Range::iterator q_it = quads.begin(); q_it != quads.end(); ++q_it )
187  {
188  int i = *q_it - start_quad;
189  for( int j = 0; j < 3; j++ )
190  tag2_ptr[3 * i + j] /= (double)tag3_ptr[i]; // Normalize by # verts
191  if( tag1_ptr[3 * i] != tag2_ptr[3 * i] || tag1_ptr[3 * i + 1] != tag2_ptr[3 * i + 1] ||
192  tag1_ptr[3 * i + 2] != tag2_ptr[3 * i + 2] )
193  {
194  cout << "Tag1, tag2 disagree for element " << *q_it + i << endl;
195  n_dis++;
196  }
197  }
198  if( !n_dis ) cout << "All tags agree, success!" << endl;
199 
200  // Ok, we're done, shut down MOAB
201  delete mbImpl;
202 
203  return 0;
204 }

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