[MOAB-dev] r1676 - MOAB/trunk/parallel

kraftche at mcs.anl.gov kraftche at mcs.anl.gov
Fri Mar 21 10:20:15 CDT 2008


Author: kraftche
Date: 2008-03-21 10:20:14 -0500 (Fri, 21 Mar 2008)
New Revision: 1676

Added:
   MOAB/trunk/parallel/pcomm_unit.cpp
Modified:
   MOAB/trunk/parallel/MBParallelComm.cpp
   MOAB/trunk/parallel/Makefile.am
Log:
o Add support for pack/unpack of variable-length tags
o Fix pack with no elements
o Fix unpack with no sets
o Remove arbitrary limitation on tag name length
   (send fortran-style string.)
o Add unit tests for pack_buffer/unpack_buffer
   - test for bit tags commented out because it fails.
 



Modified: MOAB/trunk/parallel/MBParallelComm.cpp
===================================================================
--- MOAB/trunk/parallel/MBParallelComm.cpp	2008-03-21 14:54:55 UTC (rev 1675)
+++ MOAB/trunk/parallel/MBParallelComm.cpp	2008-03-21 15:20:14 UTC (rev 1676)
@@ -16,12 +16,15 @@
 
 #include <iostream>
 #include <algorithm>
+#include <numeric>
 
 #define MIN(a,b) (a < b ? a : b)
 const bool debug = false;
 
 #include <math.h>
+#include <assert.h>
 
+
 extern "C" 
 {
 #include "minmax.h"
@@ -29,8 +32,6 @@
 #include "tuple_list.h"
 }
 
-#include <assert.h>
-
 #ifdef USE_MPI
 #include "mpi.h"
 #endif
@@ -436,7 +437,9 @@
   }
   
   MBRange::const_iterator end_rit = start_rit;
-  if (allRanges[0].size() == entities.size()) return MB_SUCCESS;
+  // If we return now because there are no elements, then MBMAXTYPE
+  // doesn't get appended and the unpack code fails.  -- j.kraftcheck
+  //if (allRanges[0].size() == entities.size()) return MB_SUCCESS;
 
   std::vector<MBRange>::iterator allr_it = allRanges.begin();
   
@@ -769,6 +772,9 @@
 
   MBRange set_handles, new_sets;
   UNPACK_RANGE(buff_ptr, set_handles);
+  if (set_handles.empty()) // assertion below fails if no sets, so check now.
+    return MB_SUCCESS;
+    
   std::vector<MBEntityHandle> members;
   int num_ents;
   optionsVec.resize(set_handles.size());
@@ -880,6 +886,8 @@
   count = 0;
   unsigned char *orig_buff_ptr = buff_ptr;
   MBErrorCode result;
+  std::vector<int> var_len_sizes;
+  std::vector<const void*> var_len_values;
 
   if (just_count) {
 
@@ -890,36 +898,48 @@
 
     for (std::vector<MBTag>::iterator tag_it = all_tags.begin(); tag_it != all_tags.end(); tag_it++) {
       const TagInfo *tinfo = tagServer->get_tag_info(*tag_it);
-      int this_count = 0;
       MBRange tmp_range;
       result = tagServer->get_entities(*tag_it, tmp_range);
       RR("Failed to get entities for tag in pack_tags.");
       tmp_range = tmp_range.intersect(whole_range);
-      if (!tmp_range.empty()) this_count = tmp_range.size() * tinfo->get_size();
+      
+      if (tmp_range.empty())
+        continue;
 
-      if (0 == this_count) continue;
-
         // ok, we'll be sending this tag
       allTags.push_back(*tag_it);
 
         // default value
       count += sizeof(int);
-      if (NULL != tinfo->default_value()) count += tinfo->get_size();
+      if (NULL != tinfo->default_value()) 
+        count += tinfo->default_value_size();
       
         // size, type, data type
       count += 3*sizeof(int);
       
         // name
-      count += 64;
+      count += sizeof(int);
+      count += tinfo->get_name().size();
 
-      if (!tmp_range.empty()) {
-        tagRanges.push_back(tmp_range);
-          // range of tag
-        count += sizeof(int) + 2 * num_subranges(tmp_range) * sizeof(MBEntityHandle);
+      tagRanges.push_back(tmp_range);
+        // range of tag
+      count += sizeof(int) + 2 * num_subranges(tmp_range) * sizeof(MBEntityHandle);
+      
+      if (tinfo->get_size() == MB_VARIABLE_LENGTH) {
+        const int num_ent = tmp_range.size();
+        // send a tag size for each entity
+        count += num_ent * sizeof(int);
+        // send tag data for each entity
+        var_len_sizes.resize( num_ent );
+        var_len_values.resize( num_ent );
+        result = tagServer->get_data( *tag_it, tmp_range, &var_len_values[0], &var_len_sizes[0] );
+        RR("Failed to get lenghts of variable-length tag values.");
+        count += std::accumulate( var_len_sizes.begin(), var_len_sizes.end(), 0 );
       }
-      
-          // tag data values for range or vector
-      count += this_count;
+      else {
+            // tag data values for range or vector
+        count += tmp_range.size() * tinfo->get_size();
+      }
     }
 
       // number of tags
@@ -948,18 +968,31 @@
         PACK_INT(buff_ptr, 0);
       }
       else {
-        PACK_INT(buff_ptr, 1);
-        PACK_VOID(buff_ptr, tinfo->default_value(), tinfo->get_size());
+        PACK_INT(buff_ptr, tinfo->default_value_size());
+        PACK_VOID(buff_ptr, tinfo->default_value(), tinfo->default_value_size());
       }
       
         // name
-      PACK_CHAR_64(buff_ptr, tinfo->get_name().c_str());
+      PACK_INT(buff_ptr, tinfo->get_name().size() );
+      PACK_VOID(buff_ptr, tinfo->get_name().c_str(), tinfo->get_name().size());
       
-      tag_data.resize(tr_it->size() * tinfo->get_size());
-      result = mbImpl->tag_get_data(*tag_it, *tr_it, &tag_data[0]);
-      RR("Failed to get tag data in pack_tags.");
+      const size_t num_ent = tr_it->size();
       PACK_RANGE(buff_ptr, (*tr_it));
-      PACK_VOID(buff_ptr, &tag_data[0], tr_it->size()*tinfo->get_size());
+      if (tinfo->get_size() == MB_VARIABLE_LENGTH) {
+        var_len_sizes.resize( num_ent, 0 );
+        var_len_values.resize( num_ent, 0 );
+        result = mbImpl->tag_get_data(*tag_it, *tr_it, &var_len_values[0], &var_len_sizes[0] );
+        RR("Failed to get variable-length tag data in pack_tags.");
+        PACK_INTS(buff_ptr, &var_len_sizes[0], num_ent);
+        for (int i = 0; i < num_ent; ++i)
+          PACK_VOID(buff_ptr, var_len_values[i], var_len_sizes[i]);
+      }
+      else {
+        tag_data.resize(num_ent * tinfo->get_size());
+        result = mbImpl->tag_get_data(*tag_it, *tr_it, &tag_data[0]);
+        RR("Failed to get tag data in pack_tags.");
+        PACK_VOID(buff_ptr, &tag_data[0], num_ent*tinfo->get_size());
+      }
       tr_it++;
     }
 
@@ -983,6 +1016,8 @@
   int num_tags;
   UNPACK_INT(buff_ptr, num_tags);
   std::vector<MBEntityHandle> tag_ents;
+  std::vector<const void*> var_len_vals;
+  std::vector<int> var_lengths;
 
   for (int i = 0; i < num_tags; i++) {
     
@@ -996,25 +1031,32 @@
     UNPACK_INT(buff_ptr, tag_data_type);
       
       // default value
-    int has_def_value;
-    UNPACK_INT(buff_ptr, has_def_value);
+    int def_val_size;
+    UNPACK_INT(buff_ptr, def_val_size);
     void *def_val_ptr = NULL;
-    if (1 == has_def_value) {
+    if (def_val_size) {
       def_val_ptr = buff_ptr;
-      buff_ptr += tag_size;
+      buff_ptr += def_val_size;
     }
     
       // name
-    char *tag_name = reinterpret_cast<char *>(buff_ptr);
-    buff_ptr += 64;
+    int name_len;
+    UNPACK_INT(buff_ptr, name_len);
+    std::string tag_name( reinterpret_cast<char*>(buff_ptr), name_len );
+    buff_ptr += name_len;
 
       // create the tag
-    result = mbImpl->tag_create(tag_name, tag_size, (MBTagType) tag_type, 
-                                (MBDataType) tag_data_type, tag_handle,
-                                def_val_ptr);
+    if (tag_size == MB_VARIABLE_LENGTH) 
+      result = mbImpl->tag_create_variable_length( tag_name.c_str(), (MBTagType)tag_type,
+                                                   (MBDataType)tag_data_type, tag_handle,
+                                                   def_val_ptr, def_val_size );
+    else
+      result = mbImpl->tag_create(tag_name.c_str(), tag_size, (MBTagType) tag_type, 
+                                  (MBDataType) tag_data_type, tag_handle,
+                                  def_val_ptr);
     if (MB_ALREADY_ALLOCATED == result) {
         // already allocated tag, check to make sure it's the same size, type, etc.
-      const TagInfo *tag_info = tagServer->get_tag_info(tag_name);
+      const TagInfo *tag_info = tagServer->get_tag_info(tag_name.c_str());
       MBTagType this_type;
       result = mbImpl->tag_get_type(tag_handle, this_type);
       if (tag_size != tag_info->get_size() ||
@@ -1050,11 +1092,39 @@
       *vit = handle_map.find(*rit);
       assert(0 != *vit);
     }
-        
-    result = mbImpl->tag_set_data(tag_handle, &tag_ents[0], 
-                                  tag_range.size(), buff_ptr);
-    RR("Trouble setting range-based tag data when unpacking tag.");
-    buff_ptr += tag_range.size() * tag_size;
+    
+    if (tag_size == MB_VARIABLE_LENGTH) {
+      const size_t num_ents = tag_ents.size();
+        // Be careful of alignment here.  If the integers are aligned
+        // in the buffer, we can use them directly.  Otherwise we must
+        // copy them.
+      const int* size_arr;
+      if (((size_t)buff_ptr)%4) {
+        var_lengths.resize( num_ents );
+        memcpy( &var_lengths[0], buff_ptr, num_ents*sizeof(int) );
+        size_arr = &var_lengths[0];
+      }
+      else {
+        size_arr = reinterpret_cast<const int*>(buff_ptr);
+      }
+      buff_ptr += sizeof(int) * num_ents;
+      
+        // get pointers into buffer for each tag value
+      var_len_vals.resize(tag_ents.size());
+      for (std::vector<MBEntityHandle>::size_type i = 0; i < tag_ents.size(); ++i) {
+        var_len_vals[i] = buff_ptr;
+        buff_ptr += size_arr[i];
+      }
+      result = mbImpl->tag_set_data( tag_handle, &tag_ents[0], tag_ents.size(), 
+                                     &var_len_vals[0], size_arr );
+      RR("Trouble setting tag data when unpacking variable-length tag.");
+    }
+    else {
+      result = mbImpl->tag_set_data(tag_handle, &tag_ents[0], 
+                                    tag_range.size(), buff_ptr);
+      RR("Trouble setting range-based tag data when unpacking tag.");
+      buff_ptr += tag_range.size() * tag_size;
+    }
   }
   
   return MB_SUCCESS;

Modified: MOAB/trunk/parallel/Makefile.am
===================================================================
--- MOAB/trunk/parallel/Makefile.am	2008-03-21 14:54:55 UTC (rev 1675)
+++ MOAB/trunk/parallel/Makefile.am	2008-03-21 15:20:14 UTC (rev 1676)
@@ -18,6 +18,7 @@
 # Conditional sources
 MOAB_PARALLEL_SRCS =
 MOAB_PARALLEL_HDRS =
+MOAB_PARALLEL_TEST = 
 if USE_MPI
   MOAB_PARALLEL_SRCS += \
      MBParallelComm.cpp \
@@ -42,6 +43,7 @@
   MOAB_PARALLEL_HDRS += WriteHDF5Parallel.hpp
 endif
 
+  MOAB_PARALLEL_TEST += pcomm_unit
 endif
 
 # The list of source files, and any header files that do not need to be installed
@@ -58,3 +60,8 @@
 #moab_test_LDADD = $(top_builddir)/libMOAB.la
 #moab_test_DEPENDENCIES = test/mb_big_test.g test/cell1.gen test/cell2.gen $(top_builddir)/libMOAB.la
 
+check_PROGRAMS = $(MOAB_PARALLEL_TEST)
+TESTS = $(MOAB_PARALLEL_TEST)
+pcomm_unit_SOURCES = pcomm_unit.cpp
+pcomm_unit_LDADD = $(top_builddir)/libMOAB.la
+

Added: MOAB/trunk/parallel/pcomm_unit.cpp
===================================================================
--- MOAB/trunk/parallel/pcomm_unit.cpp	                        (rev 0)
+++ MOAB/trunk/parallel/pcomm_unit.cpp	2008-03-21 15:20:14 UTC (rev 1676)
@@ -0,0 +1,1506 @@
+#include "MBParallelComm.hpp"
+#include "MBCore.hpp"
+#include "TestUtil.hpp"
+
+#ifdef USE_MPI
+#  include <mpi.h>
+#endif
+
+/** Test pack/unpack of vertices */
+void test_pack_vertices();
+/** Test pack/unpack of elements */
+void test_pack_elements();
+/** Test pack/unpack of higher-order elements */
+void test_pack_higher_order();
+/** Test pack/unpack of polygons & polyhedra */
+void test_pack_poly();
+/** Test pack/unpack of entity sets */
+void test_pack_sets_simple();
+/** Test pack/unpack of entity sets including implicit packing of set contents */
+void test_pack_set_contents();
+/** Test pack/unpack of entity sets containing entity sets */
+void test_pack_sets_of_sets();
+/** Test pack/unpack of set parent/child relations */
+void test_pack_set_parent_child();
+/** Test pack/unpack tag values*/
+void test_pack_tag_data();
+/** Test pack/unpack tag values*/
+void test_pack_bit_tag_data();
+/** Test pack/unpack of variable length tag values*/
+void test_pack_variable_length_tag();
+/** Test pack/unpack tag values*/
+void test_pack_tag_handle_data();
+
+int main( int argc, char* argv[] )
+{
+#ifdef USE_MPI
+  MPI_Init( &argc, &argv );
+#endif
+
+  int num_err = 0;
+  num_err += RUN_TEST( test_pack_vertices );
+  num_err += RUN_TEST( test_pack_elements );
+  num_err += RUN_TEST( test_pack_higher_order );
+  num_err += RUN_TEST( test_pack_poly );
+  num_err += RUN_TEST( test_pack_sets_simple );
+  num_err += RUN_TEST( test_pack_set_contents );
+  num_err += RUN_TEST( test_pack_sets_of_sets );
+  num_err += RUN_TEST( test_pack_set_parent_child );
+  num_err += RUN_TEST( test_pack_tag_data );
+  //num_err += RUN_TEST( test_pack_bit_tag_data );
+  num_err += RUN_TEST( test_pack_variable_length_tag );
+  num_err += RUN_TEST( test_pack_tag_handle_data );
+  
+#ifdef USE_MPI
+  MPI_Finalize();
+#endif
+  return num_err;
+}
+
+/* Utility method: pack mesh data, clear moab instance, and unpack */
+void pack_unpack_mesh( MBCore& moab, MBRange& entities )
+{
+  MBErrorCode rval;
+  if (entities.empty()) {
+    rval = moab.get_entities_by_handle( 0, entities );
+    CHECK_ERR(rval);
+  }
+  
+  MBRange tmp_range;
+  MBParallelComm pcomm( &moab );
+  int size = 0;
+  rval = pcomm.pack_buffer( entities, false, true, true, tmp_range, size );
+  CHECK_ERR(rval);
+  pcomm.buffer_size( size );
+  rval = pcomm.pack_buffer( entities, false, true, false, tmp_range, size );
+  CHECK_ERR(rval);
+  
+  std::vector<unsigned char> buffer;
+  pcomm.take_buffer( buffer );
+  // Apparently returned size is bogus.
+  // CHECK_EQUAL( (size_t)size, buffer.size() );
+  
+  moab.~MBCore();
+  new (&moab) MBCore();
+  
+  pcomm.~MBParallelComm();
+  new (&pcomm) MBParallelComm( &moab, buffer );
+  
+  entities.clear();
+  rval = pcomm.unpack_buffer( entities );
+  CHECK_ERR(rval);
+}
+void pack_unpack_mesh( MBCore& moab )
+{
+  MBRange empty;
+  pack_unpack_mesh( moab, empty );
+}
+
+/* Utility method -- check expected sizes */
+void check_sizes( MBInterface& moab,
+                  int num_vtx,
+                  int num_edge,
+                  int num_tri,
+                  int num_quad,
+                  int num_polygon,
+                  int num_tet,
+                  int num_pyr,
+                  int num_wedge,
+                  int num_knife,
+                  int num_hex,
+                  int num_polyhedron )
+{
+  int count;
+  MBErrorCode rval;
+  
+  rval = moab.get_number_entities_by_type( 0, MBVERTEX, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_vtx, count );
+
+  rval = moab.get_number_entities_by_type( 0, MBEDGE, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_edge, count );
+
+  rval = moab.get_number_entities_by_type( 0, MBTRI, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_tri, count );
+
+  rval = moab.get_number_entities_by_type( 0, MBQUAD, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_quad, count );
+
+  rval = moab.get_number_entities_by_type( 0, MBPOLYGON, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_polygon, count );
+
+  rval = moab.get_number_entities_by_type( 0, MBTET, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_tet, count );
+
+  rval = moab.get_number_entities_by_type( 0, MBPYRAMID, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_pyr, count );
+
+  rval = moab.get_number_entities_by_type( 0, MBPRISM, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_wedge, count );
+
+  rval = moab.get_number_entities_by_type( 0, MBKNIFE, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_knife, count );
+
+  rval = moab.get_number_entities_by_type( 0, MBHEX, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_hex, count );
+
+  rval = moab.get_number_entities_by_type( 0, MBPOLYHEDRON, count );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_polyhedron, count );
+}
+
+/* Create a simple mesh for use in tests */
+void create_simple_grid( MBInterface& moab, unsigned x, unsigned y, unsigned z );
+void create_simple_grid( MBInterface& moab, unsigned xyz = 3 )
+{
+  create_simple_grid( moab, xyz, xyz, xyz );
+}
+void create_simple_grid( MBInterface& moab, unsigned x, unsigned y, unsigned z )
+{
+  MBErrorCode rval;
+  MBEntityHandle verts[x*y*z];
+  for (unsigned k = 0; k < z; ++k)
+    for (unsigned j = 0; j < y; ++j)
+      for (unsigned i = 0; i < x; ++i) {
+        const double coords[3] = { i, j, k };
+        rval = moab.create_vertex( coords, verts[x*y*k + x*j + i] );
+        CHECK_ERR(rval);
+      }
+  
+  MBEntityHandle elems[(x-1)*(y-1)*(z-1)];
+  for (unsigned k = 0; k < (z-1); ++k)
+    for (unsigned j = 0; j < (y-1); ++j)
+      for (unsigned i = 0; i < (x-1); ++i) {
+        const size_t idx = (size_t)i + (size_t)j*x + (size_t)k*x*y; 
+        const MBEntityHandle conn[8] = { verts[idx        ],
+                                         verts[idx      +1],
+                                         verts[idx    +x+1],
+                                         verts[idx    +x  ],
+                                         verts[idx+x*y    ],
+                                         verts[idx+x*y  +1],
+                                         verts[idx+x*y+x+1],
+                                         verts[idx+x*y+x  ] };
+        rval = moab.create_element( MBHEX, conn, 8, elems[(x-1)*(y-1)*k + (x-1)*j + i] );
+        CHECK_ERR(rval);
+      }
+}
+
+
+void test_pack_vertices()
+{
+  MBCore moab;
+  MBErrorCode rval;
+  MBRange verts;
+  
+  const size_t num_verts = 4;
+  const double coords[3*num_verts] = { -0.5, -1./3, 0.0,
+                                        0.5, -1./3, 0.0,
+                                        0.0,  2./3, 0.0,
+                                        0.0,  0.0,  0.745356 };
+  
+  rval = moab.create_vertices( coords, num_verts, verts );
+  CHECK_ERR(rval);
+  
+  pack_unpack_mesh( moab, verts );
+  CHECK_EQUAL( num_verts, verts.size() );
+  
+  double coords2[3*num_verts];
+  rval = moab.get_coords( verts, coords2 );
+  CHECK_ERR(rval);
+  
+  std::vector<bool> seen( num_verts, false );
+  for (unsigned i = 0; i < num_verts; ++i) {
+    unsigned j;
+    for (j = 0; j < num_verts; ++j) 
+      if (coords[3*j  ] == coords2[3*i  ] &&
+          coords[3*j+1] == coords2[3*i+1] &&
+          coords[3*j+2] == coords2[3*i+2])
+        break;
+    CHECK( j < num_verts );
+    CHECK( !seen[j] );
+    seen[j] = true;
+  }
+}
+
+void test_pack_elements()
+{
+  MBCore moab;
+  MBErrorCode rval;
+  MBRange elems;
+  
+    // define some vertices
+  const size_t num_verts = 12;
+  MBEntityHandle verts[num_verts];
+  const double hex_corners[3*num_verts] = { -1, -1, -1,
+                                             1, -1, -1,
+                                             1,  1, -1,
+                                            -1,  1, -1,
+                                            -1, -1,  0,
+                                             1, -1,  0,
+                                             1,  1,  0,
+                                            -1,  1,  0,
+                                            -1, -1,  1,
+                                             1, -1,  1,
+                                             1,  1,  1,
+                                            -1,  1,  1 };
+  for (size_t i = 0; i < num_verts; ++i) {
+    rval = moab.create_vertex( hex_corners + 3*i, verts[i] );
+    CHECK_ERR(rval);
+  }
+  
+    // define two adjacent hexes
+  const size_t num_hex = 2;
+  MBEntityHandle hexes[num_hex];
+  rval = moab.create_element( MBHEX, verts, 8, hexes[0] );
+  CHECK_ERR(rval);
+  elems.insert( hexes[0] );
+  rval = moab.create_element( MBHEX, verts+4, 8, hexes[1] );
+  CHECK_ERR(rval);
+  elems.insert( hexes[1] );
+  
+    // define a single quad on the adjacent sides of the hexes
+  const size_t num_quad = 1;
+  MBEntityHandle quad;
+  rval = moab.create_element( MBQUAD, verts+4, 4, quad );
+  CHECK_ERR(rval);
+  elems.insert( quad );
+  
+    // define a decomposition of the first hex into 5 tets
+  const size_t num_tet = 5;
+  MBEntityHandle tets[num_tet];
+  MBEntityHandle tet_conn[num_tet][4] = 
+                               { { verts[0], verts[1], verts[3], verts[4] },
+                                 { verts[1], verts[2], verts[3], verts[6] },
+                                 { verts[1], verts[3], verts[4], verts[6] },
+                                 { verts[4], verts[6], verts[5], verts[1] },
+                                 { verts[7], verts[6], verts[4], verts[3] } };
+  rval = moab.create_element( MBTET, tet_conn[0], 4, tets[0] );
+  CHECK_ERR(rval);
+  elems.insert( tets[0] );
+  rval = moab.create_element( MBTET, tet_conn[1], 4, tets[1] );
+  CHECK_ERR(rval);
+  elems.insert( tets[1] );
+  rval = moab.create_element( MBTET, tet_conn[2], 4, tets[2] );
+  CHECK_ERR(rval);
+  elems.insert( tets[2] );
+  rval = moab.create_element( MBTET, tet_conn[3], 4, tets[3] );
+  CHECK_ERR(rval);
+  elems.insert( tets[3] );
+  rval = moab.create_element( MBTET, tet_conn[4], 4, tets[4] );
+  CHECK_ERR(rval);
+  elems.insert( tets[4] );
+  
+    // define the 4 shared faces of the above tets as tris
+    // (the faces of the 3rd tet)
+  const size_t num_tri = 4;
+  MBEntityHandle tris[num_tri];
+  MBEntityHandle tri_conn[num_tri][3] = { { verts[3], verts[1], verts[4] },
+                                          { verts[1], verts[6], verts[4] },
+                                          { verts[1], verts[3], verts[6] },
+                                          { verts[3], verts[4], verts[6] } };
+  rval = moab.create_element( MBTRI, tri_conn[0], 3, tris[0] );
+  CHECK_ERR(rval);
+  elems.insert( tris[0] );
+  rval = moab.create_element( MBTRI, tri_conn[1], 3, tris[1] );
+  CHECK_ERR(rval);
+  elems.insert( tris[1] );
+  rval = moab.create_element( MBTRI, tri_conn[2], 3, tris[2] );
+  CHECK_ERR(rval);
+  elems.insert( tris[2] );
+  rval = moab.create_element( MBTRI, tri_conn[3], 3, tris[3] );
+  CHECK_ERR(rval);
+  elems.insert( tris[3] );
+  
+    // define a decomposition of the second hex into two wedges
+  const size_t num_wedge = 2;
+  MBEntityHandle wedges[num_wedge];
+  MBEntityHandle wedge_conn[num_wedge][6] = {
+    { verts[4], verts[5], verts[7], verts[8], verts[9], verts[11] },
+    { verts[5], verts[6], verts[7], verts[9], verts[10],verts[11] } };
+  rval = moab.create_element( MBPRISM, wedge_conn[0], 6, wedges[0] );
+  CHECK_ERR(rval);
+  elems.insert( wedges[0] );
+  rval = moab.create_element( MBPRISM, wedge_conn[1], 6, wedges[1] );
+  CHECK_ERR(rval);
+  elems.insert( wedges[1] );
+  
+    // define a pyramid
+  MBEntityHandle pyr;
+  rval = moab.create_element( MBPYRAMID, verts, 5, pyr );
+  CHECK_ERR(rval);
+  elems.insert( pyr );
+  
+    // pack and unpack mesh
+  pack_unpack_mesh( moab, elems );
+  
+    // check_counts
+  check_sizes( moab, num_verts, 0, num_tri, num_quad, 0, 
+                     num_tet, 1, num_wedge, 0, num_hex, 0 );
+
+    // get connectivity for two hexes and a quad
+  MBRange range;
+  const MBEntityHandle *conn1, *conn2, *conn3;
+  int len1, len2, len3;
+  rval = moab.get_entities_by_type( 0, MBHEX, range );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_hex, range.size() );
+  rval = moab.get_connectivity( range.front(), conn1, len1, true );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( 8, len1 );
+  rval = moab.get_connectivity( range.back(),  conn2, len2, true );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( 8, len2 );
+  range.clear();
+  rval = moab.get_entities_by_type( 0, MBQUAD, range );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_quad, range.size() );
+  rval = moab.get_connectivity( range.front(), conn3, len3, true );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( 4, len3 );
+  
+    // Check if hexes are reversed
+  if (conn1[0] == conn2[4]) {
+    std::swap( conn1, conn2 );
+  }
+  
+    // Check consistant connectivity between hexes
+  CHECK_EQUAL( conn1[4], conn2[0] );
+  CHECK_EQUAL( conn1[5], conn2[1] );
+  CHECK_EQUAL( conn1[6], conn2[2] );
+  CHECK_EQUAL( conn1[7], conn2[3] );
+    // Check connectivity of quad on shared face
+  CHECK_EQUAL( conn1[4], conn3[0] );
+  CHECK_EQUAL( conn1[5], conn3[1] );
+  CHECK_EQUAL( conn1[6], conn3[2] );
+  CHECK_EQUAL( conn1[7], conn3[3] );
+    // Check coordinates
+  const MBEntityHandle combined[12] = { conn1[0], conn1[1], conn1[2], conn1[3],
+                                        conn3[0], conn3[1], conn3[2], conn3[3],
+                                        conn2[4], conn2[5], conn2[6], conn2[7] };
+  double coords[36];
+  rval = moab.get_coords( combined, 12, coords );
+  CHECK_ERR(rval);
+  for (int i = 0; i < 36; ++i) {
+    CHECK_REAL_EQUAL( hex_corners[i], coords[i], 1e-12 );
+  }
+}
+
+void test_pack_higher_order()
+{
+  MBCore moab;
+  MBErrorCode rval;
+  MBRange elems;
+  
+    // define coordinates for a pyramid decomposed
+    // into two 10-node tets
+  const size_t num_vert = 14;
+  const double coords[3*num_vert] = { -1, -1, 0,
+                                       0, -1, 0,
+                                       1, -1, 0,
+                                       1,  0, 0,
+                                       1,  1, 0,
+                                       0,  1, 0,
+                                      -1,  1, 0,
+                                      -1,  0, 0,
+                                       0,  0, 0, 
+                                       0,  0, 1,
+                                     -.5, -.5, .5,
+                                      .5, -.5, .5,
+                                      .5,  .5, .5,
+                                     -.5,  .5, .5 };
+  MBEntityHandle verts[num_vert];
+  for (size_t i = 0; i < num_vert; ++i) {
+    rval = moab.create_vertex( coords + 3*i, verts[i] );
+    CHECK_ERR(rval);
+  }
+  
+    // define two tets
+  const size_t num_tet = 2;
+  MBEntityHandle tet_conn[2][10] = {
+   { verts[ 0], verts[ 4], verts[ 9], verts[2],
+     verts[ 8], verts[12], verts[10],
+     verts[ 1], verts[ 3], verts[11] }, 
+   { verts[ 0], verts[ 9], verts[ 4], verts[6],
+     verts[10], verts[12], verts[ 8],
+     verts[ 7], verts[13], verts[ 5] } };
+     
+  MBEntityHandle tets[num_tet];
+  rval = moab.create_element( MBTET, tet_conn[0], 10, tets[0] );
+  CHECK_ERR(rval);
+  elems.insert( tets[0] );
+  rval = moab.create_element( MBTET, tet_conn[1], 10, tets[1] );
+  CHECK_ERR(rval);
+  elems.insert( tets[1] );
+   
+    // define interior tri face
+  const size_t num_tri = 1;
+  MBEntityHandle tri_conn[6] = 
+    { verts[0], verts[4], verts[9],
+      verts[8], verts[12],verts[10] };
+  MBEntityHandle tri;
+  rval = moab.create_element( MBTRI, tri_conn, 6, tri );
+  CHECK_ERR(rval);
+  elems.insert( tri );
+  
+    // pack and unpack mesh
+  pack_unpack_mesh( moab, elems );
+  
+    // check_counts
+  check_sizes( moab, num_vert, 0, num_tri, 0, 0, num_tet, 0, 0, 0, 0, 0 );
+
+    // get connectivity for two tets and a tri
+  MBRange range;
+  const MBEntityHandle *conn1, *conn2, *conn3;
+  int len1, len2, len3;
+  rval = moab.get_entities_by_type( 0, MBTET, range );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_tet, range.size() );
+  rval = moab.get_connectivity( range.front(), conn1, len1, false );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( 10, len1 );
+  rval = moab.get_connectivity( range.back(),  conn2, len2, false );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( 10, len2 );
+  range.clear();
+  rval = moab.get_entities_by_type( 0, MBTRI, range );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_tri, range.size() );
+  rval = moab.get_connectivity( range.front(), conn3, len3, false );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( 6, len3 );
+  
+    // The first face of one of the tets is in the 
+    // same order as the tri.
+  if (conn3[1] != conn1[1])
+    std::swap( conn1, conn2 );
+  
+    // check consistant connectivity for face shared by tets
+  CHECK_EQUAL( conn1[0], conn2[0] );
+  CHECK_EQUAL( conn1[1], conn2[2] );
+  CHECK_EQUAL( conn1[2], conn2[1] );
+  CHECK_EQUAL( conn1[4], conn2[6] );
+  CHECK_EQUAL( conn1[5], conn2[5] );
+  CHECK_EQUAL( conn1[6], conn2[4] );
+    // check connsistant connectivity between tet face and tri
+  CHECK_EQUAL( conn1[0], conn3[0] );
+  CHECK_EQUAL( conn1[1], conn3[1] );
+  CHECK_EQUAL( conn1[2], conn3[2] );
+  CHECK_EQUAL( conn1[4], conn3[3] );
+  CHECK_EQUAL( conn1[5], conn3[4] );
+  CHECK_EQUAL( conn1[6], conn3[5] );
+  
+    // order vertex handles corresponding to original coordinate list
+  const MBEntityHandle combined[num_vert] = {
+    conn1[0], 
+    conn1[7],
+    conn1[3],
+    conn1[8],
+    conn1[1],
+    conn2[9],
+    conn2[3],
+    conn2[7],
+    conn1[4],
+    conn1[2],
+    conn1[6],
+    conn1[9],
+    conn1[5],
+    conn2[8] };
+  double coords2[3*num_vert];
+  rval = moab.get_coords( combined, num_vert, coords2 );
+  CHECK_ERR(rval);
+  
+    // check vertex coordinates
+  for (int i = 0; i < 36; ++i) {
+    CHECK_REAL_EQUAL( coords[i], coords2[i], 1e-12 );
+  }
+}
+
+
+void test_pack_poly()
+{
+  MBCore moab;
+  MBErrorCode rval;
+  MBRange elems;
+  
+    // define a pyramid w/ a octagonal base
+  const double a = 0.5;
+  const double b = 1+sqrt(2.0)/2.0;
+  const size_t num_vert = 9;
+  const double coords[3*num_vert] = {
+    -a, -b, 0,
+     a, -b, 0,
+     b, -a, 0,
+     b,  a, 0,
+     a,  b, 0,
+    -a,  b, 0,
+    -b,  a, 0,
+    -b, -a, 0,
+     0,  0, 1 };
+  MBEntityHandle verts[num_vert];
+  for (size_t i = 0; i < num_vert; ++i) {
+    rval = moab.create_vertex( coords + 3*i, verts[i] );
+    CHECK_ERR(rval);
+  }
+  
+    // define octagonal base
+  const size_t num_polygon = 1;
+  MBEntityHandle octagon;
+  rval = moab.create_element( MBPOLYGON, verts, 8, octagon );
+  CHECK_ERR(rval);
+  
+    // define triangular sides
+  const size_t num_tri = num_vert-1;
+  MBEntityHandle tri[num_tri];
+  for (size_t i = 0; i < num_tri; ++i) {
+    const MBEntityHandle conn[3] = { verts[i], verts[(i+1)%num_tri], verts[num_tri] };
+    rval = moab.create_element( MBTRI, conn, 3, tri[i] );
+    CHECK_ERR(rval);
+  }
+  
+    // define the octagon-based pyramid
+  const size_t num_polyhedron = 1;
+  MBEntityHandle polyhedron;
+  MBEntityHandle all_faces[num_vert];
+  all_faces[0] = octagon;
+  std::copy( tri, tri+num_tri, all_faces+1 );
+  rval = moab.create_element( MBPOLYHEDRON, all_faces, num_vert, polyhedron );
+  CHECK_ERR(rval);
+  
+    // pack and unpack the mesh
+  elems.clear();
+  elems.insert( polyhedron );
+  elems.insert( octagon );
+  std::copy( tri, tri+num_tri, mb_range_inserter(elems) );
+  pack_unpack_mesh( moab, elems );
+  
+    // check counts
+  check_sizes( moab, num_vert, 0, num_tri, 0, num_polygon, 
+                     0, 0, 0, 0, 0, num_polyhedron );
+  
+    // get entities
+  MBRange range;
+  rval = moab.get_entities_by_type( 0, MBPOLYHEDRON, range );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_polyhedron, range.size() );
+  polyhedron = range.front();
+  
+  range.clear();
+  rval = moab.get_entities_by_type( 0, MBPOLYGON, range );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_polygon, range.size() );
+  octagon = range.front();
+  
+  range.clear();
+  rval = moab.get_entities_by_type( 0, MBTRI, range );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_tri, range.size() );
+  
+    // check coords of octagon vertices
+  const MBEntityHandle* oct_conn;
+  int eight = 0;
+  rval = moab.get_connectivity( octagon, oct_conn, eight );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( 8, eight );
+  double oct_coords[3*8];
+  rval = moab.get_coords( oct_conn, 8, oct_coords );
+  CHECK_ERR(rval);
+  for (int i = 0; i < 3*8; ++i) {
+    CHECK_REAL_EQUAL( coords[i], oct_coords[i], 1e-12 );
+  }
+  
+    // check faces of polyhedron
+  std::vector<MBEntityHandle> volconn;
+  rval = moab.get_connectivity( &polyhedron, 1, volconn );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( num_tri + 1, volconn.size() );
+  CHECK_EQUAL( volconn[0], octagon );
+  for (MBRange::iterator i = range.begin(); i != range.end(); ++i) {
+    CHECK( std::find(volconn.begin(), volconn.end(), *i) != volconn.end() );
+  }
+}
+
+void test_pack_sets_simple()
+{
+  MBCore moab;
+  MBErrorCode rval;
+  create_simple_grid( moab, 3 );  
+
+    // delete any existing sets
+  MBRange sets;
+  rval = moab.get_entities_by_type( 0, MBENTITYSET, sets );
+  CHECK_ERR(rval);
+  if (!sets.empty()) {
+    rval = moab.delete_entities( sets );
+    CHECK_ERR(rval);
+  }
+  
+    // get all entities
+  MBRange entities;
+  rval = moab.get_entities_by_handle( 0, entities );
+  CHECK_ERR(rval);
+    // expect 8 elements and 27 vertices
+  CHECK_EQUAL( (MBEntityHandle)35, entities.size() );
+  CHECK_EQUAL( 27u, entities.num_of_type( MBVERTEX ) );
+  CHECK_EQUAL( 8u, entities.num_of_type( MBHEX ) );
+  
+  
+    // create five sets:
+    // 1) one with all the elements and vertices,
+    // 2) one with half of the elements, 
+    // 3) one with the other half of the elements, 
+    // 4) one with a single vertex, 
+    // 5) an empty set, 
+  MBEntityHandle all_set, half1_set, half2_set, vertex_set, empty_set;
+  const unsigned int all_opt = MESHSET_SET | MESHSET_TRACK_OWNER,
+                     half1_opt = MESHSET_SET,
+                     half2_opt = MESHSET_SET,
+                     vertex_opt = MESHSET_ORDERED,
+                     empty_opt = MESHSET_ORDERED | MESHSET_TRACK_OWNER;
+  rval = moab.create_meshset( all_opt, all_set );
+  CHECK_ERR(rval);
+  entities.insert( all_set );
+  rval = moab.create_meshset( half1_opt, half1_set );
+  CHECK_ERR(rval);
+  entities.insert( half1_set );
+  rval = moab.create_meshset( half2_opt, half2_set );
+  CHECK_ERR(rval);
+  entities.insert( half2_set );
+  rval = moab.create_meshset( vertex_opt, vertex_set );
+  CHECK_ERR(rval);
+  entities.insert( vertex_set );
+  rval = moab.create_meshset( empty_opt, empty_set );
+  CHECK_ERR(rval);
+  entities.insert( empty_set );
+
+  MBRange elems, verts, half;
+  rval = moab.get_entities_by_type( 0, MBVERTEX, verts );
+  CHECK_ERR(rval);
+  rval = moab.get_entities_by_type( 0, MBHEX, elems );
+  CHECK_ERR(rval);
+  
+  rval = moab.add_entities( all_set, verts );
+  CHECK_ERR(rval);
+  rval = moab.add_entities( all_set, elems );
+  CHECK_ERR(rval);
+  half.merge( elems.begin(), elems.begin() += elems.size() / 2 );
+  rval = moab.add_entities( half1_set, half );
+  CHECK_ERR(rval);
+  half.clear();
+  half.merge( elems.begin() += elems.size() / 2, elems.end() );
+  rval = moab.add_entities( half2_set, half );
+  CHECK_ERR(rval);
+  MBEntityHandle vert = verts.front();
+  rval = moab.add_entities( vertex_set, &vert, 1 );
+  CHECK_ERR(rval);
+  
+    // do pack and unpack
+  pack_unpack_mesh( moab, entities );
+  
+    // get entities by type
+  verts.clear();
+  rval = moab.get_entities_by_type( 0, MBVERTEX, verts );
+  CHECK_ERR(rval);
+  elems.clear();
+  rval = moab.get_entities_by_type( 0, MBHEX, elems );
+  CHECK_ERR(rval);
+  sets.clear();
+  rval = moab.get_entities_by_type( 0, MBENTITYSET, sets );
+  CHECK_ERR(rval);
+  
+  CHECK_EQUAL( (MBEntityHandle)27, verts.size() );
+  CHECK_EQUAL( (MBEntityHandle)8, elems.size() );
+  CHECK_EQUAL( (MBEntityHandle)5, sets.size() );
+  
+    // guess which is which
+  empty_set = all_set = vertex_set = half1_set = half2_set = 0;
+  for (MBRange::iterator i = sets.begin(); i != sets.end(); ++i) {
+    int num_vtx, num_elem;
+    rval = moab.get_number_entities_by_type( *i, MBVERTEX, num_vtx );
+    CHECK_ERR(rval);
+    rval = moab.get_number_entities_by_type( *i, MBHEX, num_elem );
+    CHECK_ERR(rval);
+    if (num_vtx == 0) {
+      if (num_elem == 0) {
+        CHECK_EQUAL( (MBEntityHandle)0, empty_set );
+        empty_set = *i;
+      }
+      else if (!half1_set) {
+        half1_set = *i;
+      }
+      else {
+        CHECK_EQUAL( (MBEntityHandle)0, half2_set );
+        half2_set = *i;
+      }
+    }
+    else if (num_vtx == 1) {
+      CHECK_EQUAL( 0, num_elem );
+      CHECK_EQUAL( (MBEntityHandle)0, vertex_set );
+      vertex_set = *i;
+    }
+    else {
+      CHECK_EQUAL( 8, num_elem );
+      CHECK_EQUAL( 27, num_vtx );
+      CHECK_EQUAL( (MBEntityHandle)0, all_set );
+      all_set = *i;
+    }
+  }
+  
+    // check set options
+  unsigned opt;
+  rval = moab.get_meshset_options( all_set, opt );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( all_opt, opt );
+  rval = moab.get_meshset_options( half1_set, opt );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( half1_opt, opt );
+  rval = moab.get_meshset_options( half2_set, opt );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( half2_opt, opt );
+  rval = moab.get_meshset_options( vertex_set, opt );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( vertex_opt, opt );
+  rval = moab.get_meshset_options( empty_set, opt );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( empty_opt, opt );
+}
+
+void test_pack_set_contents()
+{
+  MBCore moab;
+  MBErrorCode rval;
+  create_simple_grid( moab, 3 );  
+
+    // delete any existing sets
+  MBRange sets;
+  rval = moab.get_entities_by_type( 0, MBENTITYSET, sets );
+  CHECK_ERR(rval);
+  if (!sets.empty()) {
+    rval = moab.delete_entities( sets );
+    CHECK_ERR(rval);
+  }
+  
+    // get all vertices
+  MBRange vertices;
+  rval = moab.get_entities_by_type( 0, MBVERTEX, vertices );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (MBEntityHandle)27, vertices.size() );
+    // create meshset containing vertices
+  MBEntityHandle set;
+  rval = moab.create_meshset( MESHSET_SET, set );
+  CHECK_ERR(rval);
+  rval = moab.add_entities( set, vertices );
+  CHECK_ERR(rval);
+  
+    // pack and unpack range containing only set handle.
+    // Will fail unless we also pass in set contents explicitly
+  MBRange entities( vertices );
+  entities.insert( set );
+  pack_unpack_mesh( moab, entities );
+  
+    // expect single set in mesh
+  entities.clear();
+  rval = moab.get_entities_by_type( 0, MBENTITYSET, entities );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (MBEntityHandle)1, entities.size() );
+  set = entities.front();
+  
+    // expect 27 vertices in mesh
+  vertices.clear();
+  rval = moab.get_entities_by_type( 0, MBVERTEX, vertices );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (MBEntityHandle)27, vertices.size() );
+  
+    // expect set to contain all 27 vertices
+  vertices.clear();
+  rval = moab.get_entities_by_type( set, MBVERTEX, vertices );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (MBEntityHandle)27, vertices.size() );
+}
+
+void test_pack_sets_of_sets()
+{
+  MBCore moab;
+  MBErrorCode rval;
+ 
+    // delete any existing sets
+  MBRange sets;
+  rval = moab.get_entities_by_type( 0, MBENTITYSET, sets );
+  CHECK_ERR(rval);
+  if (!sets.empty()) {
+    rval = moab.delete_entities( sets );
+    CHECK_ERR(rval);
+  }
+ 
+    // create three sets such that set2 contains set1, and set3 contains
+    // both set1 and set2
+  MBEntityHandle set1, set2, set3;
+  sets.clear();
+  rval = moab.create_meshset( MESHSET_ORDERED, set1 );
+  CHECK_ERR(rval);
+  sets.insert( set1 );
+  rval = moab.create_meshset( MESHSET_SET, set2 );
+  CHECK_ERR(rval);
+  rval = moab.add_entities( set2, sets );
+  CHECK_ERR(rval);
+  sets.insert( set2 );
+  rval = moab.create_meshset( MESHSET_SET, set3 );
+  CHECK_ERR(rval);
+  rval = moab.add_entities( set3, sets );
+  CHECK_ERR(rval);
+  sets.insert( set3 );
+  
+    // pack and unpack
+  pack_unpack_mesh( moab, sets );
+  
+    // get sets
+  sets.clear();
+  rval = moab.get_entities_by_type( 0, MBENTITYSET, sets );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (MBEntityHandle)3, sets.size() );
+  
+    // figure out which is which
+  set1 = set2 = set3 = 0;
+  for (MBRange::iterator i = sets.begin(); i != sets.end(); ++i) {
+    int count;
+    rval = moab.get_number_entities_by_type( *i, MBENTITYSET, count );
+    CHECK_ERR(rval);
+    CHECK( count >= 0 && count <= 2 );
+    switch (count) {
+      case 0:
+        CHECK_EQUAL( (MBEntityHandle)0, set1 );
+        set1 = *i;
+        break;
+      case 1:
+        CHECK_EQUAL( (MBEntityHandle)0, set2 );
+        set2 = *i;
+        break;
+      case 2:
+        CHECK_EQUAL( (MBEntityHandle)0, set3 );
+        set3 = *i;
+        break;
+    }
+  }
+  
+    // check that set2 contains set1
+  sets.clear();
+  rval = moab.get_entities_by_type( set2, MBENTITYSET, sets );
+  CHECK_EQUAL( (MBEntityHandle)1, sets.size() );
+  CHECK_EQUAL( set1, sets.front() );
+  
+    // check that set3 contains set1 and set2
+  sets.clear();
+  rval = moab.get_entities_by_type( set3, MBENTITYSET, sets );
+  CHECK_EQUAL( (MBEntityHandle)2, sets.size() );
+  if (sets.front() == set1) {
+    CHECK_EQUAL( set2, sets.back() );
+  }
+  else {
+    CHECK_EQUAL( set2, sets.front() );
+    CHECK_EQUAL( set1, sets.back() );
+  }
+}
+
+void test_pack_set_parent_child()
+{
+  MBCore moab;
+  MBErrorCode rval;
+ 
+    // delete any existing sets
+  MBRange sets;
+  rval = moab.get_entities_by_type( 0, MBENTITYSET, sets );
+  CHECK_ERR(rval);
+  if (!sets.empty()) {
+    rval = moab.delete_entities( sets );
+    CHECK_ERR(rval);
+  }
+ 
+    // create three sets such that set3 has a child link to
+    // set1, set2 has a parent link to set1, and such that set3 and
+    // set2 are parent and child, respectively.
+  MBEntityHandle set1, set2, set3;
+  sets.clear();
+  rval = moab.create_meshset( MESHSET_ORDERED, set1 );
+  CHECK_ERR(rval);
+  sets.insert( set1 );
+  rval = moab.create_meshset( MESHSET_SET, set2 );
+  CHECK_ERR(rval);
+  sets.insert( set2 );
+  rval = moab.create_meshset( MESHSET_SET, set3 );
+  CHECK_ERR(rval);
+  sets.insert( set3 );
+  
+  rval = moab.add_child_meshset( set3, set1 );
+  CHECK_ERR(rval);
+  rval = moab.add_parent_meshset( set2, set1 );
+  CHECK_ERR(rval);
+  rval = moab.add_parent_child( set3, set2 );
+  CHECK_ERR(rval);
+  
+    // make sure everything is valid before doing the pack/unpack
+  int count;
+  rval = moab.num_child_meshsets( set1, &count );
+  CHECK( MB_SUCCESS == rval && 0 == count );
+  rval = moab.num_child_meshsets( set2, &count );
+  CHECK( MB_SUCCESS == rval && 0 == count );
+  rval = moab.num_child_meshsets( set3, &count );
+  CHECK( MB_SUCCESS == rval && 2 == count );
+  rval = moab.num_parent_meshsets( set1, &count );
+  CHECK( MB_SUCCESS == rval && 0 == count );
+  rval = moab.num_parent_meshsets( set2, &count );
+  CHECK( MB_SUCCESS == rval && 2 == count );
+  rval = moab.num_parent_meshsets( set3, &count );
+  CHECK( MB_SUCCESS == rval && 0 == count );
+  
+    // pack and unpack
+  pack_unpack_mesh( moab, sets );
+  
+    // get sets
+  sets.clear();
+  rval = moab.get_entities_by_type( 0, MBENTITYSET, sets );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (MBEntityHandle)3, sets.size() );
+  
+    // look for a set with two child links (set3)
+  set1 = set2 = set3 = 0;
+  for (MBRange::iterator i = sets.begin(); i != sets.end(); ++i) {
+    int count;
+    rval = moab.num_child_meshsets( *i, &count );
+    CHECK_ERR(rval);
+    if (count == 2) {
+      set3 = *i;
+      break;
+    }
+  }
+  CHECK( 0 != set3 );
+  
+    // check set relations
+  std::vector<MBEntityHandle> parents, children;
+  rval = moab.get_child_meshsets( set3, children );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (std::vector<MBEntityHandle>::size_type)2, children.size() );
+  set1 = children[0];
+  set2 = children[1];
+  rval = moab.get_parent_meshsets( set1, parents );
+  CHECK_ERR(rval);
+  CHECK( parents.empty() );
+  children.clear();
+  rval = moab.get_parent_meshsets( set1, children );
+  CHECK_ERR(rval);
+  CHECK( children.empty() );
+  rval = moab.get_parent_meshsets( set2, parents );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (std::vector<MBEntityHandle>::size_type)2, parents.size() );
+  CHECK_EQUAL( set1, parents[0] );
+  CHECK_EQUAL( set3, parents[1] );
+}
+
+void test_pack_tag_data()
+{
+  MBRange::iterator i;
+  int size;
+  MBDataType type;
+  MBTagType storage;
+  MBCore moab;
+  MBInterface& mb = moab;
+  MBErrorCode rval;
+  
+  create_simple_grid( mb, 3 );  
+  MBRange verts, elems, sets;
+  rval = mb.get_entities_by_type( 0, MBVERTEX, verts );
+  CHECK_ERR(rval);
+  CHECK( !verts.empty() );
+  rval = mb.get_entities_by_type( 0, MBHEX, elems );
+  CHECK_ERR(rval);
+  CHECK( !elems.empty() );
+ 
+    // Define a sparse tag containing two integers.  For every other element
+    // in the mesh, set the tag value to the floor of the x and y
+    // coordinates of the first vertex in the elements connectivity list.
+  const char sparse_2_int_tag_name[] = "test tag 1";
+  MBTag sparse_2_int_tag;
+  rval = mb.tag_create( sparse_2_int_tag_name,
+                        2*sizeof(int),
+                        MB_TAG_SPARSE,
+                        MB_TYPE_INTEGER,
+                        sparse_2_int_tag,
+                        0 );
+  CHECK_ERR(rval);
+  bool skip = false;
+  for (i = elems.begin(); i != elems.end(); ++i, skip = !skip) {
+    if (skip)
+      continue;
+    
+    const MBEntityHandle* conn =0;
+    int len;
+    rval = mb.get_connectivity( *i, conn, len );
+    CHECK_ERR(rval);
+    double coords[3];
+    rval = mb.get_coords( conn, 1, coords );
+    CHECK_ERR(rval);
+    const int data[2] = { (int)coords[0], (int)coords[1] };
+    rval = mb.tag_set_data( sparse_2_int_tag, &*i, 1, data );
+    CHECK_ERR(rval);
+  }
+  
+    // Define a dense tag containing a single double-precision floating
+    // point value.  For each vertex, store the distance from the origin
+    // in this tag.
+  const char dense_1_double_tag_name[] = "test tag 2";
+  MBTag dense_1_double_tag;
+  rval = mb.tag_create( dense_1_double_tag_name,
+                        sizeof(double),
+                        MB_TAG_DENSE,
+                        MB_TYPE_DOUBLE,
+                        dense_1_double_tag,
+                        0 );
+  CHECK_ERR(rval);
+  for (i = verts.begin(); i != verts.end(); ++i) {
+    double coords[3];
+    rval = mb.get_coords( &*i, 1, coords );
+    CHECK_ERR(rval);
+    double val = sqrt(coords[0]*coords[0] + coords[1]*coords[1] + coords[2]*coords[2]);
+    rval = mb.tag_set_data( dense_1_double_tag, &*i, 1, &val );
+    CHECK_ERR(rval);
+  }
+ 
+    // Define a dense, opaque tag with a default value of "DEFLT".
+    // Set the tag on one element, one vertex,and one set to "TAGGD".
+  const char dense_5_opaque_tag_name[] = "This is intentionally a very long tag name in an attempt to test for an arbitrary limitations on tag name length.";
+  MBTag dense_5_opaque_tag;
+  rval = mb.tag_create( dense_5_opaque_tag_name,
+                        5,
+                        MB_TAG_DENSE,
+                        dense_5_opaque_tag,
+                        "DEFLT" );
+  CHECK_ERR(rval);
+  MBEntityHandle set;
+  rval = mb.create_meshset( MESHSET_SET, set );
+  CHECK_ERR(rval);
+  const MBEntityHandle handles[3] = { verts.front(), elems.front(), set };
+  const char data[] = "TAGGDTAGGDTAGGD";
+  rval = mb.tag_set_data( dense_5_opaque_tag, handles, 3, data );
+  CHECK_ERR(rval);
+  
+    // pack and unpack
+  MBRange ents;
+  pack_unpack_mesh( moab, ents );
+  elems.clear();
+  verts.clear();
+  sets.clear();
+  rval = mb.get_entities_by_type( 0, MBVERTEX, verts );
+  CHECK_ERR(rval);
+  rval = mb.get_entities_by_type( 0, MBHEX, elems );
+  CHECK_ERR(rval);
+  rval = mb.get_entities_by_type( 0, MBENTITYSET, sets );
+  CHECK_ERR(rval);
+  
+  
+    // check tag meta for sparse_2_int_tag
+  rval = mb.tag_get_handle( sparse_2_int_tag_name, sparse_2_int_tag );
+  CHECK_ERR(rval);
+  rval = mb.tag_get_size( sparse_2_int_tag, size );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (int)(2*sizeof(int)), size );
+  rval = mb.tag_get_type( sparse_2_int_tag, storage );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( MB_TAG_SPARSE, storage );
+  rval = mb.tag_get_data_type( sparse_2_int_tag, type );
+  CHECK_EQUAL( MB_TYPE_INTEGER, type );
+  int intdata[2];
+  rval = mb.tag_get_default_value( sparse_2_int_tag, intdata );
+  CHECK_EQUAL( MB_ENTITY_NOT_FOUND, rval );
+  
+    // check tag data for sparse_2_int_tag
+  MBRange tagged;
+  rval = mb.get_entities_by_type_and_tag( 0, MBHEX, 
+                                          &sparse_2_int_tag, 0, 1,
+                                          tagged );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (elems.size()+1) / 2, tagged.size() );
+  for (i = tagged.begin(); i != tagged.end(); ++i) {
+    rval = mb.tag_get_data( sparse_2_int_tag, &*i, 1, intdata );
+    CHECK_ERR(rval);
+    
+    const MBEntityHandle* conn =0;
+    int len;
+    rval = mb.get_connectivity( *i, conn, len );
+    CHECK_ERR(rval);
+    double coords[3];
+    rval = mb.get_coords( conn, 1, coords );
+    CHECK_ERR(rval);
+    
+    CHECK_EQUAL( (int)(coords[0]), intdata[0] );
+    CHECK_EQUAL( (int)(coords[1]), intdata[1] );
+  }
+  
+    // check tag meta for dense_1_double_tag
+  rval = mb.tag_get_handle( dense_1_double_tag_name, dense_1_double_tag );
+  CHECK_ERR(rval);
+  rval = mb.tag_get_size( dense_1_double_tag, size );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( (int)sizeof(double), size );
+  rval = mb.tag_get_type( dense_1_double_tag, storage );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( MB_TAG_DENSE, storage );
+  rval = mb.tag_get_data_type( dense_1_double_tag, type );
+  CHECK_EQUAL( MB_TYPE_DOUBLE, type );
+  double dval;
+  rval = mb.tag_get_default_value( dense_1_double_tag, &dval );
+  CHECK_EQUAL( MB_ENTITY_NOT_FOUND, rval );
+  
+    // check tag data for dense_1_double_tag
+  for (i = verts.begin(); i != verts.end(); ++i) {
+    double coords[3];
+    rval = mb.get_coords( &*i, 1, coords );
+    CHECK_ERR(rval);
+    
+    const double expected = sqrt(coords[0]*coords[0] + coords[1]*coords[1] + coords[2]*coords[2]);
+    rval = mb.tag_get_data( dense_1_double_tag, &*i, 1, &dval );
+    CHECK_ERR(rval);
+    CHECK_REAL_EQUAL( expected, dval, 1e-6 );
+  }
+  
+    // check tag meta for dense_5_opaque_tag
+  rval = mb.tag_get_handle( dense_5_opaque_tag_name, dense_5_opaque_tag );
+  CHECK_ERR(rval);
+  rval = mb.tag_get_size( dense_5_opaque_tag, size );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( 5, size );
+  rval = mb.tag_get_type( dense_5_opaque_tag, storage );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( MB_TAG_DENSE, storage );
+  rval = mb.tag_get_data_type( dense_5_opaque_tag, type );
+  CHECK_EQUAL( MB_TYPE_OPAQUE, type );
+  char odata[6]; odata[5] = '\0';
+  rval = mb.tag_get_default_value( dense_5_opaque_tag, odata );
+  CHECK_ERR( rval );
+  CHECK_EQUAL( std::string("DEFLT"), std::string(odata) );
+  
+    // count number of each type with tag set to non-default
+  int vcount = 0, ecount = 0, scount =0;
+  for (i = verts.begin(); i != verts.end(); ++i) {
+    rval = mb.tag_get_data( dense_5_opaque_tag, &*i, 1, odata );
+    CHECK_ERR(rval);
+    if (strcmp( odata, "DEFLT" )) {
+      CHECK_EQUAL( std::string("TAGGD"), std::string(odata) );
+      ++vcount;
+    }
+  }
+  CHECK_EQUAL( 1, vcount );
+  for (i = elems.begin(); i != elems.end(); ++i) {
+    rval = mb.tag_get_data( dense_5_opaque_tag, &*i, 1, odata );
+    CHECK_ERR(rval);
+    if (strcmp( odata, "DEFLT" )) {
+      CHECK_EQUAL( "TAGGD", odata );
+      ++ecount;
+    }
+  }
+  CHECK_EQUAL( 1, ecount );
+  for (i = sets.begin(); i != sets.end(); ++i) {
+    rval = mb.tag_get_data( dense_5_opaque_tag, &*i, 1, odata );
+    CHECK_ERR(rval);
+    if (strcmp( odata, "DEFLT" )) {
+      CHECK_EQUAL( "TAGGD", odata );
+      ++scount;
+    }
+  }
+  CHECK_EQUAL( 1, scount );
+}
+
+
+void test_pack_bit_tag_data()
+{
+  MBRange::iterator i;
+  MBCore moab;
+  MBInterface& mb = moab;
+  MBErrorCode rval;
+  
+    // create some mesh
+  create_simple_grid( mb, 3 );  
+  MBRange verts;
+  rval = mb.get_entities_by_type( 0, MBVERTEX, verts );
+  CHECK_ERR(rval);
+  CHECK( !verts.empty() );
+ 
+    // Create a bit tag
+  const char tag_name[] = "test bit";
+  MBTag tag;
+  rval = mb.tag_create( tag_name, 3, MB_TAG_BIT, tag, 0 );
+  CHECK_ERR(rval);
+  
+    // Set bits to 1 unless cooresponding coordinate of 
+    // vertex is zero.
+  for (i = verts.begin(); i != verts.end(); ++i) {
+    double coords[3];
+    rval = mb.get_coords( &*i, 1, coords );
+    CHECK_ERR(rval);
+    
+    unsigned char data = 0;
+    for (int j = 0; j < 3; ++j) 
+      if (fabs(coords[j]) > 1e-6)
+        data |= (1 << j);
+    rval = mb.tag_set_data( tag, &*i, 1, &data );
+    CHECK_ERR(rval);
+  }
+  
+    // pack and unpack
+  MBRange ents;
+  pack_unpack_mesh( moab, ents );
+  verts.clear();
+  rval = mb.get_entities_by_type( 0, MBVERTEX, verts );
+  CHECK_ERR(rval);
+
+    // check tag meta 
+  rval = mb.tag_get_handle( tag_name, tag );
+  CHECK_ERR(rval);
+  
+  int size;
+  rval = mb.tag_get_size( tag, size );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( 3, size );
+  
+  MBTagType storage;
+  rval = mb.tag_get_type( tag, storage );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( MB_TAG_BIT, storage );
+  
+  MBDataType type;
+  rval = mb.tag_get_data_type( tag, type );
+  CHECK_EQUAL( MB_TYPE_BIT, type );
+
+    // check tag values
+  for (i = verts.begin(); i != verts.end(); ++i) {
+    double coords[3];
+    rval = mb.get_coords( &*i, 1, coords );
+    CHECK_ERR(rval);
+    
+    unsigned char expected = 0;
+    for (int j = 0; j < 3; ++j) 
+      if (fabs(coords[j]) > 1e-6)
+        expected |= (1 << j);
+        
+    unsigned char data = (unsigned char)0xFF;
+    rval = mb.tag_get_data( tag, &*i, 1, &data );
+    CHECK_ERR(rval);
+    
+    CHECK_EQUAL( (int)expected, (int)data );
+  }
+}
+
+void test_pack_variable_length_tag()
+{
+  MBRange::iterator i;
+  MBCore moab;
+  MBInterface& mb = moab;
+  MBErrorCode rval;
+  
+    // create some mesh
+  create_simple_grid( mb, 3 );  
+  MBRange verts;
+  rval = mb.get_entities_by_type( 0, MBVERTEX, verts );
+  CHECK_ERR(rval);
+  CHECK( !verts.empty() );
+  
+    // create a variable-length tag 
+  const char* tag_name = "var_int_tag";
+  const int default_val[] = { 0xBEEF, 0xFEED, 0xDEAD, 0xBAD, 0xBEAD };
+  MBTag tag;
+  rval = mb.tag_create_variable_length( tag_name, MB_TAG_DENSE, MB_TYPE_INTEGER,
+                                        tag, default_val, sizeof(default_val) );
+  CHECK_ERR(rval);
+  
+    // for each vertex, store in the tag an integer between 1 and 3, 
+    // followed by the floor of the cooresponding number of vertex
+    // coordinates, beginning with x.
+  for (i = verts.begin(); i != verts.end(); ++i) {
+    double coords[3];
+    rval = mb.get_coords( &*i, 1, coords );
+    CHECK_ERR(rval);
+    
+    const int num_coord = 1 + *i % 3;
+    const int data_size = sizeof(int) * (num_coord + 1);
+    const int data[4] = { num_coord, (int)coords[0], (int)coords[1], (int)coords[2] };
+    const void* data_ptrs[1] = { data };
+    rval = mb.tag_set_data( tag, &*i, 1, data_ptrs, &data_size );
+    CHECK_ERR(rval);
+  }
+  
+    // pack and unpack
+  pack_unpack_mesh( moab );
+  verts.clear();
+  rval = mb.get_entities_by_type( 0, MBVERTEX, verts );
+  CHECK_ERR(rval);
+
+    // check tag meta 
+  rval = mb.tag_get_handle( tag_name, tag );
+  CHECK_ERR(rval);
+  
+  int size;
+  rval = mb.tag_get_size( tag, size );
+  CHECK_EQUAL( MB_VARIABLE_DATA_LENGTH, rval );
+  
+  MBTagType storage;
+  rval = mb.tag_get_type( tag, storage );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( MB_TAG_DENSE, storage );
+  
+  MBDataType type;
+  rval = mb.tag_get_data_type( tag, type );
+  CHECK_EQUAL( MB_TYPE_INTEGER, type );
+
+  const void* defval_ptr;
+  rval = mb.tag_get_default_value( tag, defval_ptr, size );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( sizeof(default_val), (size_t)size );
+  const int* defval_arr = reinterpret_cast<const int*>(defval_ptr);
+  for (size_t j = 0; j < sizeof(default_val)/sizeof(int); ++j)
+    CHECK_EQUAL( default_val[j], defval_arr[j] );
+  
+    // check tag values
+  for (i = verts.begin(); i != verts.end(); ++i) {
+    double coords[3];
+    rval = mb.get_coords( &*i, 1, coords );
+    CHECK_ERR(rval);
+    
+    int size;
+    const void* valptr;
+    rval = mb.tag_get_data( tag, &*i, 1, &valptr, &size );
+    CHECK_ERR(rval);
+    CHECK( (size % sizeof(int)) == 0 );
+    int count = size / sizeof(int);
+    CHECK( count > 1 );
+    CHECK( count <= 4 );
+    
+    const int* valarr = reinterpret_cast<const int*>(valptr);
+    CHECK( valarr[0] >= 1 );
+    CHECK( valarr[0] <= 3 );
+    for (int j = 0; j < valarr[0]; ++j) {
+      CHECK_EQUAL( (int)(coords[j]), valarr[j+1] );
+    }
+  }
+}
+
+  
+void test_pack_tag_handle_data()
+{
+  MBRange::iterator i;
+  MBCore moab;
+  MBInterface& mb = moab;
+  MBErrorCode rval;
+  
+    // create some mesh
+  create_simple_grid( mb, 3 );  
+  MBRange verts, elems;
+  rval = mb.get_entities_by_type( 0, MBVERTEX, verts );
+  CHECK_ERR(rval);
+  CHECK( !verts.empty() );
+  rval = mb.get_entities_by_type( 0, MBHEX, elems );
+  CHECK_ERR(rval);
+  CHECK( !elems.empty() );
+ 
+    // create a tag
+  const char* tag_name = "entity tag";
+  MBEntityHandle default_val[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+  MBTag tag;
+  rval = mb.tag_create( tag_name, 8*sizeof(MBEntityHandle), MB_TAG_SPARSE, MB_TYPE_HANDLE, tag, &default_val );
+  CHECK_ERR(rval);
+  
+    // Store on each vertex the handles of the adjacent hexes, padded
+    // with NULL handles.
+  MBEntityHandle tagdata[8*8];
+  for (i = elems.begin(); i != elems.end(); ++i) {
+    const MBEntityHandle* conn;
+    int len;
+    rval = mb.get_connectivity( *i, conn, len );
+    CHECK_ERR(rval);
+    CHECK_EQUAL( 8, len );
+    
+    rval = mb.tag_get_data( tag, conn, len, tagdata );
+    CHECK_ERR(rval);
+    
+    for (int j = 0; j < 8; ++j) {
+      MBEntityHandle* vdata = tagdata + 8*j;
+      int idx = 0;
+      while (vdata[idx]) {
+        ++idx;
+        CHECK(idx < 8);
+      }
+      vdata[idx] = *i;
+    }
+     
+    rval = mb.tag_set_data( tag, conn, len, tagdata );
+    CHECK_ERR(rval);
+  }
+  
+    // pack and unpack
+  pack_unpack_mesh( moab );
+  verts.clear();
+  rval = mb.get_entities_by_type( 0, MBVERTEX, verts );
+  CHECK_ERR(rval);
+
+    // check tag meta 
+  rval = mb.tag_get_handle( tag_name, tag );
+  CHECK_ERR(rval);
+  
+  int size;
+  rval = mb.tag_get_size( tag, size );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( 8*sizeof(MBEntityHandle), (size_t)size );
+  
+  MBTagType storage;
+  rval = mb.tag_get_type( tag, storage );
+  CHECK_ERR(rval);
+  CHECK_EQUAL( MB_TAG_SPARSE, storage );
+  
+  MBDataType type;
+  rval = mb.tag_get_data_type( tag, type );
+  CHECK_EQUAL( MB_TYPE_HANDLE, type );
+
+  rval = mb.tag_get_default_value( tag, tagdata );
+  CHECK_ERR(rval);
+  for (int j = 0; j < 8; ++j) {
+    CHECK_EQUAL( (MBEntityHandle)0, tagdata[j] );
+  }
+  
+    // check tag values
+  for (i = elems.begin(); i != elems.end(); ++i) {
+    const MBEntityHandle* conn;
+    int len;
+    rval = mb.get_connectivity( *i, conn, len );
+    CHECK_ERR(rval);
+    CHECK_EQUAL( 8, len );
+    
+    rval = mb.tag_get_data( tag, conn, len, tagdata );
+    CHECK_ERR(rval);
+    
+    for (int j = 0; j < 8; ++j) {
+      MBEntityHandle* vdata = tagdata + 8*j;
+      int idx = 0;
+      while (vdata[idx] != *i) {
+        ++idx;
+        CHECK(idx < 8);
+      }
+      vdata[idx] = 0;
+    }
+     
+    rval = mb.tag_set_data( tag, conn, len, tagdata );
+    CHECK_ERR(rval);
+  }
+  
+  for (i = verts.begin(); i != verts.end(); ++i) {
+    rval = mb.tag_get_data( tag, &*i, 1, tagdata );
+    CHECK_ERR(rval);
+    for (int j = 0; j < 8; ++j) {
+      CHECK_EQUAL( (MBEntityHandle)0, tagdata[j] );
+    }
+  }
+}




More information about the moab-dev mailing list