moab
DirectAccessNoHoles.cpp

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 MOAB_DIR=<installdir>
To run: ./DirectAccessNoHoles [-nquads <# quads>]

#include "moab/Core.hpp"
#include "moab/ProgOptions.hpp"
#include "moab/ReadUtilIface.hpp"
#include <map>
#include <iostream>
#include <assert.h>

// Error routines for use with MOAB API
#define CHKERR(CODE, MSG) do {if (MB_SUCCESS != (CODE)) {std::string errstr;  mbImpl->get_last_error(errstr);   \
        std::cerr << errstr << std::endl; std::cerr << MSG << std::endl; return CODE;}} while(false)

using namespace moab;

ErrorCode create_mesh_no_holes(Interface *mbImpl, int nquads);

int main(int argc, char **argv)
{
    // get MOAB instance
  Interface *mbImpl = new Core;
  if (NULL == mbImpl) return 1;

  int nquads = 1000;
  
    // parse options
  ProgOptions opts;
  opts.addOpt<int>(std::string("nquads,n"), std::string("Number of quads in the mesh (default = 1000"), &nquads);
  opts.parseCommandLine(argc, argv);

    // create simple structured mesh with hole, but using unstructured representation
  ErrorCode rval = create_mesh_no_holes(mbImpl, nquads); CHKERR(rval, "Trouble creating mesh.");
  
    // get all vertices and non-vertex entities
  Range verts, quads;
  rval = mbImpl->get_entities_by_handle(0, quads); CHKERR(rval, "Getting all entities.");
  verts = quads.subset_by_dimension(0);
  quads -= verts;

    // create tag1 (element-based avg), tag2 (vertex-based avg), tag3 (# connected verts)
  Tag tag1, tag2, tag3;
  rval = mbImpl->tag_get_handle("tag1", 3, MB_TYPE_DOUBLE, tag1, MB_TAG_DENSE | MB_TAG_CREAT); CHKERR(rval, "Creating tag1.");
  double def_val[3] = {0.0, 0.0, 0.0}; // need a default value for tag2 because we sum into it
  rval = mbImpl->tag_get_handle("tag2", 3, MB_TYPE_DOUBLE, tag2, MB_TAG_DENSE | MB_TAG_CREAT, def_val); CHKERR(rval, "Creating tag2.");
  int def_val_int = 0;  // need a default value for tag3 because we increment it
  rval = mbImpl->tag_get_handle("tag3", 1, MB_TYPE_INTEGER, tag3, MB_TAG_DENSE | MB_TAG_CREAT, &def_val_int); CHKERR(rval, "Creating tag3.");
  
    // Get pointers to connectivity, coordinate, tag, and adjacency arrays; each of these returns a count,
    // which should be compared to the # entities you expect to verify there's only one chunk (no holes)
  int count, vpere;
  EntityHandle *conn_ptr;
  rval = mbImpl->connect_iterate(quads.begin(), quads.end(), conn_ptr, vpere, count); CHKERR(rval, "connect_iterate.");
  assert(count == (int) quads.size()); // should end up with just one contiguous chunk of quads

  double *x_ptr, *y_ptr, *z_ptr;
  rval = mbImpl->coords_iterate(verts.begin(), verts.end(), x_ptr, y_ptr, z_ptr, count); CHKERR(rval, "coords_iterate.");
  assert(count == (int) verts.size()); // should end up with just one contiguous chunk of vertices

  double *tag1_ptr, *tag2_ptr;
  int *tag3_ptr;
  rval = mbImpl->tag_iterate(tag1, quads.begin(), quads.end(), count, (void*&)tag1_ptr); CHKERR(rval, "tag1_iterate.");
  assert(count == (int) quads.size()); // should end up with just one contiguous chunk of quads
  rval = mbImpl->tag_iterate(tag2, quads.begin(), quads.end(), count, (void*&)tag2_ptr); CHKERR(rval, "tag2_iterate.");
  assert(count == (int) quads.size()); // should end up with just one contiguous chunk of quads
  rval = mbImpl->tag_iterate(tag3, quads.begin(), quads.end(), count, (void*&)tag3_ptr); CHKERR(rval, "tag3_iterate.");
  assert(count == (int) quads.size()); // should end up with just one contiguous chunk of quads

  const std::vector<EntityHandle> **adjs_ptr;
  rval = mbImpl->adjacencies_iterate(verts.begin(), verts.end(), adjs_ptr, count); CHKERR(rval, "adjacencies_iterate.");
  assert(count == (int) verts.size()); // should end up with just one contiguous chunk of vertices
  
    // Start_ handles used to compute indices into vertex/quad arrays; can use direct subtraction because we know
    // there aren't any holes in the handle spaces for verts or quads
  EntityHandle start_vert = *verts.begin(), start_quad = *quads.begin();

    // iterate over elements, computing tag1 from coords positions
  for (int i = 0; i < nquads; i++) {
    tag1_ptr[3*i+0] = tag1_ptr[3*i+1] = tag1_ptr[3*i+2] = 0.0; // initialize position for this element
    for (int j = 0; j < vpere; j++) { // loop over vertices in this element
      int v_index = conn_ptr[vpere*i+j] - start_vert; // vert index is just the offset from start vertex
      tag1_ptr[3*i+0] += x_ptr[v_index];
      tag1_ptr[3*i+1] += y_ptr[v_index]; // sum vertex positions into tag1...
      tag1_ptr[3*i+2] += z_ptr[v_index];
    }
    tag1_ptr[3*i+0] /= vpere;
    tag1_ptr[3*i+1] /= vpere; // then normalize
    tag1_ptr[3*i+2] /= vpere;
  } // loop over elements in chunk
    
    // Iterate through vertices, summing positions into tag2 on connected elements and incrementing vertex count
  for (int v = 0; v < count; v++) {
    const std::vector<EntityHandle> *avec = *(adjs_ptr+v);
    for (std::vector<EntityHandle>::const_iterator ait = avec->begin(); ait != avec->end(); ait++) {
        // *ait is the quad handle, its index is computed by subtracting the start quad handle
      int a_ind = *ait - start_quad;
      tag2_ptr[3*a_ind+0] += x_ptr[v];   // tag on each element is 3 doubles, x/y/z
      tag2_ptr[3*a_ind+1] += y_ptr[v];
      tag2_ptr[3*a_ind+2] += z_ptr[v];
      tag3_ptr[a_ind]++;  // increment the vertex count
    }
  }
        
    // Normalize tag2 by vertex count (tag3); loop over elements using same approach as before
    // At the same time, compare values of tag1 and tag2
  int n_dis = 0;
  for (Range::iterator q_it = quads.begin(); q_it != quads.end(); q_it++) {
    int i = *q_it - start_quad;
    for (int j = 0; j < 3; j++) tag2_ptr[3*i+j] /= (double)tag3_ptr[i];  // normalize by # verts
    if (tag1_ptr[3*i] != tag2_ptr[3*i] || tag1_ptr[3*i+1] != tag2_ptr[3*i+1] || tag1_ptr[3*i+2] != tag2_ptr[3*i+2]) {
      std::cout << "Tag1, tag2 disagree for element " << *q_it + i << std::endl;
      n_dis++;
    }
  }
  if (!n_dis) std::cout << "All tags agree, success!" << std::endl;

    // Ok, we're done, shut down MOAB
  delete mbImpl;

  return 0;
}

ErrorCode create_mesh_no_holes(Interface *mbImpl, int nquads) 
{
    // first make the mesh, a 1d array of quads with left hand side x = elem_num; vertices are numbered in layers
  ReadUtilIface *read_iface;
  ErrorCode rval = mbImpl->query_interface(read_iface); CHKERR(rval, "query_interface");
  std::vector<double *> coords;
  EntityHandle start_vert, start_elem, *connect;
    // create verts, num is 2(nquads+1) because they're in a 1d row; will initialize coords in loop over quads later
  rval = read_iface->get_node_coords (3, 2*(nquads+1), 0, start_vert, coords); CHKERR(rval, "get_node_arrays");
    // create quads
  rval = read_iface->get_element_connect(nquads, 4, MBQUAD, 0, start_elem, connect); CHKERR(rval, "get_element_connect");
  for (int i = 0; i < nquads; i++) {
    coords[0][2*i] = coords[0][2*i+1] = (double) i; // x values are all i
    coords[1][2*i] = 0.0; coords[1][2*i+1] = 1.0; // y coords
    coords[2][2*i] = coords[2][2*i+1] = (double) 0.0; // z values, all zero (2d mesh)
    EntityHandle quad_v = start_vert + 2*i;
    connect[4*i+0] = quad_v;
    connect[4*i+1] = quad_v+2;
    connect[4*i+2] = quad_v+3;
    connect[4*i+3] = quad_v+1;
  }
  
    // last two vertices
  coords[0][2*nquads] = coords[0][2*nquads+1] = (double) nquads;
  coords[1][2*nquads] = 0.0; coords[1][2*nquads+1] = 1.0; // y coords
  coords[2][2*nquads] = coords[2][2*nquads+1] = (double) 0.0; // z values, all zero (2d mesh)
  
    // call a vertex-quad adjacencies function to generate vertex-element adjacencies in MOAB
  Range dum_range;
  rval = mbImpl->get_adjacencies(&start_vert, 1, 2, false, dum_range); CHKERR(rval, "get_adjacencies");
  assert(!dum_range.empty());

  return MB_SUCCESS;
}

    
  
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines