1/** @example DirectAccessNoHoles.cpp \n
2 * \brief Use direct access to MOAB data to avoid calling through API \n
3 *
4 * This example creates a 1d row of quad elements, such that all quad and vertex handles
5 * are contiguous in the handle space and in the database. Then it shows how to get access
6 * to pointers to MOAB-native data for vertex coordinates, quad connectivity, tag storage,
7 * and vertex to quad adjacency lists. This allows applications to access this data directly
8 * without going through MOAB's API. In cases where the mesh is not changing (or only mesh
9 * vertices are moving), this can save significant execution time in applications.
10 * \verbatim
11 * ----------------------
12 * | | | |
13 * | | | | ...
14 * | | | |
15 * ----------------------
16 * \endverbatim
17 * -# Initialize MOAB \n
18 * -# Create a quad mesh, as depicted above
19 * -# Create 2 dense tags (tag1, tag2) for avg position to assign to quads, and # verts per quad
20 * (tag3)
21 * -# Get connectivity, coordinate, tag1 iterators
22 * -# Iterate through quads, computing midpoint based on vertex positions, set on quad-based
23 * tag1
24 * -# Iterate through vertices, summing positions into tag2 on connected quads and incrementing
25 * vertex count
26 * -# Iterate through quads, normalizing tag2 by vertex count and comparing values of tag1 and
27 * tag2
28 *
29 * <b>To compile</b>: \n
30 * make DirectAccessNoHoles \n
31 * <b>To run</b>: ./DirectAccessNoHoles [-nquads <# quads>]\n
32 *
33 */3435#include"moab/Core.hpp"36#include"moab/ProgOptions.hpp"37#include"moab/ReadUtilIface.hpp"38#include<map>39#include<iostream>40#include<cassert>4142usingnamespace moab;
43usingnamespace std;
4445ErrorCode create_mesh_no_holes( Interface* mbImpl, int nquads );
4647intmain( int argc, char** argv )
48 {
49// Get MOAB instance50 Interface* mbImpl = new( std::nothrow ) Core;
51if( NULL == mbImpl ) return1;
5253int nquads = 1000;
5455// Parse options56 ProgOptions opts;
57 opts.addOpt< int >( string( "nquads,n" ), string( "Number of quads in the mesh (default = 1000" ), &nquads );
58 opts.parseCommandLine( argc, argv );
5960// Create simple structured mesh with hole, but using unstructured representation61 ErrorCode rval = create_mesh_no_holes( mbImpl, nquads );MB_CHK_SET_ERR( rval, "Trouble creating mesh" );
6263// Get all vertices and non-vertex entities64 Range verts, quads;
65 rval = mbImpl->get_entities_by_handle( 0, quads );MB_CHK_SET_ERR( rval, "Trouble getting all entities" );
66 verts = quads.subset_by_dimension( 0 );
67 quads -= verts;
6869// Create tag1 (element-based avg), tag2 (vertex-based avg), tag3 (# connected verts)70 Tag tag1, tag2, tag3;
71 rval = mbImpl->tag_get_handle( "tag1", 3, MB_TYPE_DOUBLE, tag1, MB_TAG_DENSE | MB_TAG_CREAT );MB_CHK_SET_ERR( rval, "Trouble creating tag1" );
72double def_val[3] = { 0.0, 0.0, 0.0 }; // need a default value for tag2 because we sum into it73 rval = mbImpl->tag_get_handle( "tag2", 3, MB_TYPE_DOUBLE, tag2, MB_TAG_DENSE | MB_TAG_CREAT, def_val );MB_CHK_SET_ERR( rval, "Trouble creating tag2" );
74int def_val_int = 0; // need a default value for tag3 because we increment it75 rval = mbImpl->tag_get_handle( "tag3", 1, MB_TYPE_INTEGER, tag3, MB_TAG_DENSE | MB_TAG_CREAT, &def_val_int );MB_CHK_SET_ERR( rval, "Trouble creating tag3" );
7677// Get pointers to connectivity, coordinate, tag, and adjacency arrays; each of these returns a78// count, which should be compared to the # entities you expect to verify there's only one chunk79// (no holes)80int count, vpere;
81 EntityHandle* conn_ptr;
82 rval = mbImpl->connect_iterate( quads.begin(), quads.end(), conn_ptr, vpere, count );MB_CHK_SET_ERR( rval, "Error in connect_iterate" );
83assert( count == (int)quads.size() ); // Should end up with just one contiguous chunk of quads8485double *x_ptr, *y_ptr, *z_ptr;
86 rval = mbImpl->coords_iterate( verts.begin(), verts.end(), x_ptr, y_ptr, z_ptr, count );MB_CHK_SET_ERR( rval, "Error in coords_iterate" );
87assert( count == (int)verts.size() ); // Should end up with just one contiguous chunk of vertices8889double *tag1_ptr, *tag2_ptr;
90int* tag3_ptr;
91 rval = mbImpl->tag_iterate( tag1, quads.begin(), quads.end(), count, (void*&)tag1_ptr );MB_CHK_SET_ERR( rval, "Error in tag1_iterate" );
92assert( count == (int)quads.size() ); // Should end up with just one contiguous chunk of quads93 rval = mbImpl->tag_iterate( tag2, quads.begin(), quads.end(), count, (void*&)tag2_ptr );MB_CHK_SET_ERR( rval, "Error in tag2_iterate" );
94assert( count == (int)quads.size() ); // Should end up with just one contiguous chunk of quads95 rval = mbImpl->tag_iterate( tag3, quads.begin(), quads.end(), count, (void*&)tag3_ptr );MB_CHK_SET_ERR( rval, "Error in tag3_iterate" );
96assert( count == (int)quads.size() ); // Should end up with just one contiguous chunk of quads9798const vector< EntityHandle >** adjs_ptr;
99 rval = mbImpl->adjacencies_iterate( verts.begin(), verts.end(), adjs_ptr, count );MB_CHK_SET_ERR( rval, "Error in adjacencies_iterate" );
100assert( count == (int)verts.size() ); // Should end up with just one contiguous chunk of vertices101// Start_ handles used to compute indices into vertex/quad arrays; can use direct subtraction102// because we know there aren't any holes in the handle spaces for verts or quads103 EntityHandle start_vert = *verts.begin(), start_quad = *quads.begin();
104105// Iterate over elements, computing tag1 from coords positions106for( int i = 0; i < nquads; i++ )
107 {
108 tag1_ptr[3 * i + 0] = tag1_ptr[3 * i + 1] = tag1_ptr[3 * i + 2] = 0.0; // Initialize position for this element109for( int j = 0; j < vpere; j++ )
110 { // Loop over vertices in this element111int v_index = conn_ptr[vpere * i + j] - start_vert; // vert index is just the offset from start vertex112 tag1_ptr[3 * i + 0] += x_ptr[v_index];
113 tag1_ptr[3 * i + 1] += y_ptr[v_index]; // Sum vertex positions into tag1...114 tag1_ptr[3 * i + 2] += z_ptr[v_index];
115 }
116 tag1_ptr[3 * i + 0] /= vpere;
117 tag1_ptr[3 * i + 1] /= vpere; // Then normalize118 tag1_ptr[3 * i + 2] /= vpere;
119 } // Loop over elements in chunk120121// Iterate through vertices, summing positions into tag2 on connected elements and incrementing122// vertex count123for( int v = 0; v < count; v++ )
124 {
125const vector< EntityHandle >* avec = *( adjs_ptr + v );
126for( vector< EntityHandle >::const_iterator ait = avec->begin(); ait != avec->end(); ++ait )
127 {
128// *ait is the quad handle, its index is computed by subtracting the start quad handle129int a_ind = *ait - start_quad;
130 tag2_ptr[3 * a_ind + 0] += x_ptr[v]; // Tag on each element is 3 doubles, x/y/z131 tag2_ptr[3 * a_ind + 1] += y_ptr[v];
132 tag2_ptr[3 * a_ind + 2] += z_ptr[v];
133 tag3_ptr[a_ind]++; // Increment the vertex count134 }
135 }
136137// Normalize tag2 by vertex count (tag3); loop over elements using same approach as before138// At the same time, compare values of tag1 and tag2139int n_dis = 0;
140for( Range::iterator q_it = quads.begin(); q_it != quads.end(); ++q_it )
141 {
142int i = *q_it - start_quad;
143for( int j = 0; j < 3; j++ )
144 tag2_ptr[3 * i + j] /= (double)tag3_ptr[i]; // Normalize by # verts145if( tag1_ptr[3 * i] != tag2_ptr[3 * i] || tag1_ptr[3 * i + 1] != tag2_ptr[3 * i + 1] ||
146 tag1_ptr[3 * i + 2] != tag2_ptr[3 * i + 2] )
147 {
148 cout << "Tag1, tag2 disagree for element " << *q_it + i << endl;
149 n_dis++;
150 }
151 }
152if( !n_dis ) cout << "All tags agree, success!" << endl;
153154// Ok, we're done, shut down MOAB155delete mbImpl;
156157return0;
158 }
159160ErrorCode create_mesh_no_holes( Interface* mbImpl, int nquads )
161 {
162// First make the mesh, a 1d array of quads with left hand side x = elem_num; vertices are163// numbered in layers164 ReadUtilIface* read_iface;
165 ErrorCode rval = mbImpl->query_interface( read_iface );MB_CHK_SET_ERR( rval, "Error in query_interface" );
166 vector< double* > coords;
167 EntityHandle start_vert, start_elem, *connect;
168// Create verts, num is 2(nquads+1) because they're in a 1d row; will initialize coords in loop169// over quads later170 rval = read_iface->get_node_coords( 3, 2 * ( nquads + 1 ), 0, start_vert, coords );MB_CHK_SET_ERR( rval, "Error in get_node_arrays" );
171// Create quads172 rval = read_iface->get_element_connect( nquads, 4, MBQUAD, 0, start_elem, connect );MB_CHK_SET_ERR( rval, "Error in get_element_connect" );
173for( int i = 0; i < nquads; i++ )
174 {
175 coords[0][2 * i] = coords[0][2 * i + 1] = (double)i; // x values are all i176 coords[1][2 * i] = 0.0;
177 coords[1][2 * i + 1] = 1.0; // y coords178 coords[2][2 * i] = coords[2][2 * i + 1] = (double)0.0; // z values, all zero (2d mesh)179 EntityHandle quad_v = start_vert + 2 * i;
180 connect[4 * i + 0] = quad_v;
181 connect[4 * i + 1] = quad_v + 2;
182 connect[4 * i + 2] = quad_v + 3;
183 connect[4 * i + 3] = quad_v + 1;
184 }
185186// Last two vertices187// Cppcheck warning (false positive): variable coords is assigned a value that is never used188 coords[0][2 * nquads] = coords[0][2 * nquads + 1] = (double)nquads;
189 coords[1][2 * nquads] = 0.0;
190 coords[1][2 * nquads + 1] = 1.0; // y coords191 coords[2][2 * nquads] = coords[2][2 * nquads + 1] = (double)0.0; // z values, all zero (2d mesh)192193// Call a vertex-quad adjacencies function to generate vertex-element adjacencies in MOAB194 Range dum_range;
195 rval = mbImpl->get_adjacencies( &start_vert, 1, 2, false, dum_range );MB_CHK_SET_ERR( rval, "Error in get_adjacencies" );
196assert( !dum_range.empty() );
197198return MB_SUCCESS;
199 }