[MOAB-dev] r1589 - MOAB/trunk

kraftche at mcs.anl.gov kraftche at mcs.anl.gov
Tue Feb 5 19:01:32 CST 2008


Author: kraftche
Date: 2008-02-05 19:01:31 -0600 (Tue, 05 Feb 2008)
New Revision: 1589

Modified:
   MOAB/trunk/ReadHDF5.cpp
   MOAB/trunk/ReadHDF5.hpp
   MOAB/trunk/WriteHDF5.cpp
   MOAB/trunk/WriteHDF5.hpp
Log:
Serial I/O for variable-length tags.


Modified: MOAB/trunk/ReadHDF5.cpp
===================================================================
--- MOAB/trunk/ReadHDF5.cpp	2008-02-06 01:00:42 UTC (rev 1588)
+++ MOAB/trunk/ReadHDF5.cpp	2008-02-06 01:01:31 UTC (rev 1589)
@@ -1088,7 +1088,7 @@
   int have_sparse;             // File contains sparse data table for tag
   hid_t hdf_type = 0;          // Type to use when reading tag data.
   int elem_size;               // Bytes required for one elem of array
-  hsize_t array_size;          // If tag is not opaque, the number of data per entity
+  int array_size;              // If tag is not opaque, the number of data per entity
   MBTag handle;                // The handle for the tag
   MBDataType mb_type;          // The MOAB data type for the data
   
@@ -1158,8 +1158,14 @@
     case mhdf_OPAQUE:
     default:
 
-      elem_size = tag_size;
-      array_size = 1;
+      if (tag_size < 0) { // variable-length
+        elem_size = 1;
+        array_size = -1;
+      }
+      else {
+        elem_size = tag_size;
+        array_size = 1;
+      }
       mb_type = MB_TYPE_OPAQUE;
       hdf_type = (hid_t)0;
       
@@ -1181,22 +1187,38 @@
 
       break;
   }
+  if (tag_size < 0)  // variable length
+    tag_size = MB_VARIABLE_LENGTH;
 
   
     // Create array type from base type if array
   if (array_size > 1)
   {
-    hdf_type = H5Tarray_create( hdf_type, 1, &array_size, NULL );
+    hsize_t tmpsize = array_size;
+    hdf_type = H5Tarray_create( hdf_type, 1, &tmpsize, NULL );
     if (hdf_type < 0)
       return MB_FAILURE;
   }  
 
   
     // If default or global/mesh value in file, read it.
+  void *default_ptr = 0, *global_ptr = 0;
+  int default_size = 0, global_size = 0;
   if (have_default || have_global)
   {
-    assert( 3*tag_size < bufferSize );
-    mhdf_getTagValues( filePtr, name, hdf_type, dataBuffer, dataBuffer + tag_size, &status );
+    if (array_size == -1) { // variable-length tag
+      default_size = have_default;
+      global_size = have_global;
+    }
+    else {
+      default_size = global_size = array_size;
+    }
+    
+    assert( (default_size + global_size) * elem_size <= bufferSize );
+    default_ptr = dataBuffer;
+    global_ptr = dataBuffer + default_size*elem_size;
+
+    mhdf_getTagValues( filePtr, name, hdf_type, default_ptr, global_ptr, &status );
     if (mhdf_isError( &status ))
     {
       readUtil->report_error( mhdf_message( &status ) );
@@ -1205,17 +1227,19 @@
     
     if (MB_TYPE_HANDLE == mb_type) {
       if (have_default) {
-        rval = convert_id_to_handle( (MBEntityHandle*)dataBuffer, array_size );
+        rval = convert_id_to_handle( (MBEntityHandle*)default_ptr, default_size );
         if (MB_SUCCESS != rval)
           have_default = 0;
       }
       if (have_global) {
-        rval = convert_id_to_handle( (MBEntityHandle*)(dataBuffer+tag_size), array_size );
+        rval = convert_id_to_handle( (MBEntityHandle*)global_ptr, global_size );
         if (MB_SUCCESS != rval)
           have_global = 0;
       }
     }
   }
+  global_size *= elem_size;
+  default_size *= elem_size;
   
   
     // Check if tag already exists
@@ -1228,7 +1252,9 @@
     MBTagType curr_store;
     
     rval = iFace->tag_get_size( handle, curr_size );
-    if (MB_SUCCESS != rval) 
+    if (MB_VARIABLE_DATA_LENGTH == rval)
+      curr_size = -1;
+    else if (MB_SUCCESS != rval)
       return rval;
       
     rval = iFace->tag_get_data_type( handle, curr_type );
@@ -1251,8 +1277,12 @@
     // Create the tag if it doesn't exist
   else if (MB_TAG_NOT_FOUND == rval)
   {
-    rval = iFace->tag_create( name, tag_size, (MBTagType)storage, mb_type,
-                              handle, have_default ? dataBuffer : 0 );
+    if (tag_size == MB_VARIABLE_LENGTH)
+      rval = iFace->tag_create_variable_length( name, (MBTagType)storage, mb_type,
+                                                handle, default_ptr, default_size );
+    else
+      rval = iFace->tag_create( name, tag_size, (MBTagType)storage, mb_type,
+                                handle, default_ptr );
     if (MB_SUCCESS != rval)
       return rval;
   }
@@ -1261,15 +1291,19 @@
     return rval;
     
   if (have_global) {
-    rval = iFace->tag_set_data( handle, 0, 0, dataBuffer + tag_size );
+    rval = iFace->tag_set_data( handle, 0, 0, &global_ptr, &global_size );
     if (MB_SUCCESS != rval)
       return rval;
   }
   
     // Read tag data
   MBErrorCode tmp = MB_SUCCESS;
-  if (have_sparse)
-    tmp = read_sparse_tag( handle, hdf_type, tag_size, mb_type == MB_TYPE_HANDLE );
+  if (have_sparse) {
+    if (tag_size == MB_VARIABLE_LENGTH)
+      tmp = read_var_len_tag( handle, hdf_type, mb_type == MB_TYPE_HANDLE );
+    else 
+      tmp = read_sparse_tag( handle, hdf_type, tag_size, mb_type == MB_TYPE_HANDLE );
+  }
   rval = read_dense_tag( handle, hdf_type, tag_size, mb_type == MB_TYPE_HANDLE );
   
   
@@ -1442,7 +1476,7 @@
   std::string name;
   MBErrorCode rval;
   long num_values;
-  hid_t data[2];
+  hid_t data[3];
   MBTagType mbtype;
   assert ((hdf_read_type == 0) || (H5Tget_size(hdf_read_type) == read_size));
   
@@ -1555,6 +1589,122 @@
   return MB_SUCCESS;
 }
 
+MBErrorCode ReadHDF5::read_var_len_tag( MBTag tag_handle,
+                                        hid_t hdf_read_type,
+                                        bool is_handle_type )
+{
+  mhdf_Status status;
+  std::string name;
+  MBErrorCode rval;
+  long num_values;
+  hid_t data[3];
+  MBTagType mbtype;
+    // hdf_read_type is NULL (zero) for opaque tag data.
+  long elem_size = hdf_read_type ? H5Tget_size( hdf_read_type ) : 1;
+  if (elem_size < 1) // invalid type handle?
+    return MB_FAILURE;
+  
+  rval = iFace->tag_get_name( tag_handle, name );
+  if (MB_SUCCESS != rval)
+    return rval;
+  
+  rval = iFace->tag_get_type( tag_handle, mbtype );
+  if (MB_SUCCESS != rval)
+    return rval;
+  
+  mhdf_openSparseTagData( filePtr, name.c_str(), &num_values, data, &status );
+  if (mhdf_isError( &status ) )
+  {
+    readUtil->report_error( mhdf_message( &status ) );
+    return MB_FAILURE;
+  }
+  
+    // Process each entity individually
+  MBEntityHandle id;
+  long offset, prev_offset = 0;
+  for (long i = 0; i < num_values; ++i) {
+      // read entity ID
+    mhdf_readSparseTagEntities( data[0], i, 1, handleType, &id, &status );
+    if (mhdf_isError( &status ))
+    {
+      readUtil->report_error( mhdf_message( &status ) );
+      mhdf_closeData( filePtr, data[0], &status );
+      mhdf_closeData( filePtr, data[1], &status );
+      mhdf_closeData( filePtr, data[2], &status );
+      return MB_FAILURE;
+    }
+      // convert entity ID to MBEntityHandle
+    rval = convert_id_to_handle( &id, 1 );
+    if (MB_SUCCESS != rval)
+    {
+      mhdf_closeData( filePtr, data[0], &status );
+      mhdf_closeData( filePtr, data[1], &status );
+      mhdf_closeData( filePtr, data[2], &status );
+      return rval;
+    }
+      // read end index of tag value
+    mhdf_readSparseTagIndices( data[2], i, 1, H5T_NATIVE_LONG, &offset, &status );
+    if (mhdf_isError( &status ))
+    {
+      readUtil->report_error( mhdf_message( &status ) );
+      mhdf_closeData( filePtr, data[0], &status );
+      mhdf_closeData( filePtr, data[1], &status );
+      mhdf_closeData( filePtr, data[2], &status );
+      return MB_FAILURE;
+    }
+      // calculate length of tag value
+    ++offset;
+    int count = (int)(offset - prev_offset);
+    assert( count * elem_size <= bufferSize );
+    mhdf_readSparseTagValues( data[1], prev_offset, count, hdf_read_type, dataBuffer, &status );
+    if (mhdf_isError( &status ))
+    {
+      readUtil->report_error( mhdf_message( &status ) );
+      mhdf_closeData( filePtr, data[0], &status );
+      mhdf_closeData( filePtr, data[1], &status );
+      mhdf_closeData( filePtr, data[2], &status );
+      return MB_FAILURE;
+    }
+      // for handle-type tags, convert file IDs to MBEntityHandles in tag data
+    if (is_handle_type)
+    {
+      rval = convert_id_to_handle( (MBEntityHandle*)dataBuffer, count );
+      if (MB_SUCCESS != rval)
+      {
+        mhdf_closeData( filePtr, data[0], &status );
+        mhdf_closeData( filePtr, data[1], &status );
+        mhdf_closeData( filePtr, data[2], &status );
+        return rval;
+      }
+    }
+      // set tag data
+    const void* ptrarr[1] = { dataBuffer };
+    int bytes = count * elem_size;
+    rval = iFace->tag_set_data( tag_handle, &id, 1, ptrarr, &bytes );
+    if (MB_SUCCESS != rval)
+    {
+      mhdf_closeData( filePtr, data[0], &status );
+      mhdf_closeData( filePtr, data[1], &status );
+      mhdf_closeData( filePtr, data[2], &status );
+      return rval;
+    }
+      // iterate
+    prev_offset = offset;
+  }
+  
+  mhdf_closeData( filePtr, data[0], &status );
+  if (mhdf_isError( &status ) )
+    readUtil->report_error( mhdf_message( &status ) );
+  mhdf_closeData( filePtr, data[1], &status );
+  if (mhdf_isError( &status ) )
+    readUtil->report_error( mhdf_message( &status ) );
+  mhdf_closeData( filePtr, data[2], &status );
+  if (mhdf_isError( &status ) )
+    readUtil->report_error( mhdf_message( &status ) );
+
+  return MB_SUCCESS;
+}
+
 MBErrorCode ReadHDF5::convert_id_to_handle( const ElemSet& elems,
                                             MBEntityHandle* array,
                                             size_t size )

Modified: MOAB/trunk/ReadHDF5.hpp
===================================================================
--- MOAB/trunk/ReadHDF5.hpp	2008-02-06 01:00:42 UTC (rev 1588)
+++ MOAB/trunk/ReadHDF5.hpp	2008-02-06 01:01:31 UTC (rev 1589)
@@ -139,6 +139,11 @@
                                hid_t hdf_read_type,
                                size_t read_size,
                                bool is_handle_type );
+  
+  //! Read variable-length tag for all entities.
+  MBErrorCode read_var_len_tag( MBTag tag_handle,
+                                hid_t hdf_read_type,
+                                bool is_handle_type );
                                
   MBErrorCode read_qa( MBEntityHandle& import_set_out );
                                

Modified: MOAB/trunk/WriteHDF5.cpp
===================================================================
--- MOAB/trunk/WriteHDF5.cpp	2008-02-06 01:00:42 UTC (rev 1588)
+++ MOAB/trunk/WriteHDF5.cpp	2008-02-06 01:01:31 UTC (rev 1589)
@@ -117,6 +117,16 @@
     return MB_FAILURE;                                      \
 } while(false)                                               
 
+#define CHK_MHDF_ERR_3( A, B )                              \
+do if ( mhdf_isError( &(A) )) {                             \
+    writeUtil->report_error( "%s\n", mhdf_message( &(A) ) );\
+    myassert(0);                                            \
+    mhdf_closeData( filePtr, (B)[0], &(A) );                \
+    mhdf_closeData( filePtr, (B)[1], &(A) );                \
+    mhdf_closeData( filePtr, (B)[2], &(A) );                \
+    return MB_FAILURE;                                      \
+} while(false)                                               
+
 #define CHK_MHDF_ERR_2C( A, B, C, D )                       \
 do if ( mhdf_isError( &(A) )) {                             \
     writeUtil->report_error( "%s\n", mhdf_message( &(A) ) );\
@@ -146,6 +156,16 @@
   return (A);                              \
 } while(false)
 
+#define CHK_MB_ERR_3( A, B, C )            \
+do if (MB_SUCCESS != (A)) {                \
+  mhdf_closeData( filePtr, (B)[0], &(C) ); \
+  mhdf_closeData( filePtr, (B)[1], &(C) ); \
+  mhdf_closeData( filePtr, (B)[2], &(C) ); \
+  write_finished();                        \
+  myassert(0);                             \
+  return (A);                              \
+} while(false)
+
 #define CHK_MB_ERR_2C( A, B, C, D, E )          \
 do if (MB_SUCCESS != (A)) {                     \
   mhdf_closeData( filePtr, (B), &(E) );         \
@@ -430,10 +450,16 @@
 
     // Write tags
   for (t_itor = tagList.begin(); t_itor != tagList.end(); ++t_itor)
-    if (t_itor->write)
-      if (write_sparse_tag( *t_itor ) != MB_SUCCESS)
+    if (t_itor->write) {
+      int size;
+      if (MB_VARIABLE_DATA_LENGTH == iFace->tag_get_size( t_itor->tag_id, size ))
+        result = write_var_len_tag( *t_itor );
+      else
+        result = write_sparse_tag( *t_itor );
+      if (MB_SUCCESS != result)
         goto write_fail;
-
+    }
+    
 DEBUGOUT("Closing file.\n");
 
     // Clean up and exit.
@@ -1378,36 +1404,12 @@
 
 */
 
-MBErrorCode WriteHDF5::write_sparse_tag( const SparseTag& tag_data )
+MBErrorCode WriteHDF5::write_sparse_ids( const SparseTag& tag_data,
+                                         hid_t id_table )
 {
   MBErrorCode rval;
   mhdf_Status status;
-  hid_t tables[2];
-  std::string name;
-  int mb_size;
-  MBTagType mb_type;
-  MBDataType mb_data_type;
-  long table_size;
-  
-    //get tag properties from moab
-  if (MB_SUCCESS != iFace->tag_get_name( tag_data.tag_id, name )    ||
-      MB_SUCCESS != iFace->tag_get_type( tag_data.tag_id, mb_type ) ||
-      MB_SUCCESS != iFace->tag_get_size( tag_data.tag_id, mb_size ) ||
-      MB_SUCCESS != iFace->tag_get_data_type( tag_data.tag_id, mb_data_type ))
-    return MB_FAILURE;
-  if (mb_type == MB_TAG_BIT)
-    mb_size = 1;
 
-DEBUGOUT((std::string("Tag: ") + name + "\n").c_str());
-  
-    //open tables to write info
-  mhdf_openSparseTagData( filePtr,
-                          name.c_str(),
-                          &table_size,
-                          tables,
-                          &status);
-  CHK_MHDF_ERR_0(status);
-  assert( tag_data.range.size() + tag_data.offset <= (unsigned long)table_size );
 
     // Set up data buffer for writing IDs
   size_t chunk_size = bufferSize / sizeof(id_t);
@@ -1431,27 +1433,67 @@
     assert(range.size() == (unsigned)count);
     
     rval = iFace->tag_get_data( idTag, range, id_buffer );
-    CHK_MB_ERR_2( rval, tables, status );
+    CHK_MB_ERR_0( rval );
     
       // write the data
-    mhdf_writeSparseTagEntities( tables[0], offset, count, id_type, 
+    mhdf_writeSparseTagEntities( id_table, offset, count, id_type, 
                                  id_buffer, &status );
-    CHK_MHDF_ERR_2( status, tables );
+    CHK_MHDF_ERR_0( status );
    
     offset += count;
   } // while (remaining)
+
+  return MB_SUCCESS;
+}
+
+MBErrorCode WriteHDF5::write_sparse_tag( const SparseTag& tag_data )
+{
+  MBErrorCode rval;
+  mhdf_Status status;
+  hid_t tables[3];
+  std::string name;
+  int mb_size;
+  MBTagType mb_type;
+  MBDataType mb_data_type;
+  long table_size;
+  
+    //get tag properties from moab
+  if (MB_SUCCESS != iFace->tag_get_name( tag_data.tag_id, name )    ||
+      MB_SUCCESS != iFace->tag_get_type( tag_data.tag_id, mb_type ) ||
+      MB_SUCCESS != iFace->tag_get_size( tag_data.tag_id, mb_size ) ||
+      MB_SUCCESS != iFace->tag_get_data_type( tag_data.tag_id, mb_data_type ))
+    return MB_FAILURE;
+  if (mb_size <= 0)
+    return MB_FAILURE;
+  if (mb_type == MB_TAG_BIT)
+    mb_size = 1;
+
+DEBUGOUT((std::string("Tag: ") + name + "\n").c_str());
+  
+    //open tables to write info
+  mhdf_openSparseTagData( filePtr,
+                          name.c_str(),
+                          &table_size,
+                          tables,
+                          &status);
+  CHK_MHDF_ERR_0(status);
+  assert( tag_data.range.size() + tag_data.offset <= (unsigned long)table_size );
+
+    // Write IDs for tagged entities
+  rval = write_sparse_ids( tag_data, tables[0] );
+  CHK_MB_ERR_2( rval, tables, status );
   mhdf_closeData( filePtr, tables[0], &status );
-  CHK_MHDF_ERR_0(status);
+  CHK_MHDF_ERR_1(status, tables[1]);
   
     // Set up data buffer for writing tag values
-  chunk_size = bufferSize / mb_size;
+  size_t chunk_size = bufferSize / mb_size;
   assert( chunk_size > 0 );
   char* tag_buffer = (char*)dataBuffer;
   
     // Write the tag values
-  remaining = tag_data.range.size();
-  offset = tag_data.offset;
-  iter = tag_data.range.begin();
+  size_t remaining = tag_data.range.size();
+  size_t offset = tag_data.offset;
+  MBRange::const_iterator iter = tag_data.range.begin();
   while (remaining)
   {
       // write "chunk_size" blocks of data
@@ -1460,7 +1502,7 @@
     memset( tag_buffer, 0, count * mb_size );
     MBRange::const_iterator stop = iter;
     stop += count;
-    range.clear();
+    MBRange range;
     range.merge( iter, stop );
     iter = stop;
     assert(range.size() == (unsigned)count);
@@ -1499,6 +1541,91 @@
   return MB_SUCCESS;
 }
 
+MBErrorCode WriteHDF5::write_var_len_tag( const SparseTag& tag_data )
+{
+  MBErrorCode rval;
+  mhdf_Status status;
+  hid_t tables[3];
+  std::string name;
+  long table_size;
+  
+    //get tag properties from moab
+  if (MB_SUCCESS != iFace->tag_get_name( tag_data.tag_id, name ))
+    return MB_FAILURE;
+    
+    // get type and size information
+  int mb_size, type_size, file_size;
+  MBDataType mb_data_type;
+  mhdf_TagDataType file_type;
+  hid_t hdf_type;
+  if (MB_SUCCESS != get_tag_size( tag_data.tag_id, 
+                                  mb_data_type,
+                                  mb_size,
+                                  type_size,
+                                  file_size,
+                                  file_type,
+                                  hdf_type ))
+    return MB_FAILURE;
+  
+  if (mb_data_type == MB_TYPE_BIT) //can't do variable-length bit tags
+    return MB_FAILURE;
+  if (mb_size != MB_VARIABLE_LENGTH)
+    return MB_FAILURE;
+
+DEBUGOUT((std::string("Tag: ") + name + "\n").c_str());
+  
+    //open tables to write info
+  mhdf_openSparseTagData( filePtr,
+                          name.c_str(),
+                          &table_size,
+                          tables,
+                          &status);
+  CHK_MHDF_ERR_0(status);
+  assert( tag_data.range.size() + tag_data.offset <= (unsigned long)table_size );
+
+    // Write IDs for tagged entities
+  rval = write_sparse_ids( tag_data, tables[0] );
+  CHK_MB_ERR_2( rval, tables, status );
+  mhdf_closeData( filePtr, tables[0], &status );
+  CHK_MHDF_ERR_2(status, tables + 1);
+  
+    // Write each tag value separately
+  size_t indx_offset = tag_data.offset;
+  size_t data_offset = tag_data.varDataOffset;
+  int size;
+  unsigned long idx;
+  const void* ptr;
+  for (MBRange::const_iterator i = tag_data.range.begin(); 
+       i!= tag_data.range.end(); ++i, ++indx_offset) {
+       
+    rval = iFace->tag_get_data( tag_data.tag_id, &*i, 1, &ptr, &size );
+    CHK_MB_ERR_2(rval, tables + 1, status);
+    
+      // Convert MBEntityHandles to file ids
+    if (mb_data_type == MB_TYPE_HANDLE) {
+      assert( size < bufferSize );
+      memcpy( dataBuffer, ptr, size );
+      convert_handle_tag( iFace, idTag, dataBuffer, size / sizeof(MBEntityHandle) );
+      ptr = dataBuffer;
+    }
+    
+    mhdf_writeSparseTagValues( tables[1], data_offset, size/type_size, hdf_type, ptr, &status );
+    CHK_MHDF_ERR_2(status, tables + 1);
+    
+    idx = data_offset + size/type_size - 1;
+    mhdf_writeSparseTagIndices( tables[2], indx_offset, 1, H5T_NATIVE_ULONG, &idx, &status );
+    CHK_MHDF_ERR_2(status, tables + 1);
+    data_offset += size/type_size;
+  }
+    
+  mhdf_closeData( filePtr, tables[1], &status );
+  CHK_MHDF_ERR_1(status, tables[2]);
+  mhdf_closeData( filePtr, tables[2], &status );
+  CHK_MHDF_ERR_0(status);
+  
+  return MB_SUCCESS;
+}
+
 MBErrorCode WriteHDF5::write_qa( std::vector<std::string>& list )
 {
   const char* app = "MOAB";
@@ -1623,6 +1750,7 @@
     SparseTag tag_data;
     tag_data.tag_id = *t_itor;
     tag_data.offset = 0;
+    tag_data.varDataOffset = 0;
     tagList.push_back( tag_data );
   }
   
@@ -1652,7 +1780,12 @@
     result = iFace->get_entities_by_type_and_tag( 0, MBENTITYSET, &handle, NULL, 1, range );
     CHK_MB_ERR_0(result);
     td_iter->range.merge( range.intersect( setSet.range ) );
-    
+
+/* This breaks for variable-length tags, is slow, and is questionable.
+   Is it really better to not write the tag at all, as opposed to writing
+   NULL handles?  If the tag has a default value, this would result in 
+   the tag value changing to the default, which isn't correct.
+       
       // For tags containing entity handles, skip values if
       // handle doesn't reference something being written to the file.
       // If the tag contains multiple handle values, write it if any one
@@ -1681,10 +1814,10 @@
           i = td_iter->range.erase( i );
       }
     }
+*/
   
     td_iter->write = !td_iter->range.empty();
   }
-  
   return MB_SUCCESS;
 }
 
@@ -1816,7 +1949,7 @@
   const std::list<SparseTag>::iterator tag_end = tagList.end();
   for ( ; tag_iter != tag_end; ++tag_iter)
   {
-    rval = create_tag( tag_iter->tag_id, tag_iter->range.size() );
+    rval = create_tag( *tag_iter );
     CHK_MB_ERR_0(rval);
   } // for(tags)
   
@@ -1963,132 +2096,256 @@
   return MB_SUCCESS;
 }
 
-MBErrorCode WriteHDF5::create_tag( MBTag tag_id, id_t num_sparse_entities )
+MBErrorCode WriteHDF5::get_tag_size( MBTag tag,
+                                     MBDataType& moab_type,
+                                     int& num_bytes,
+                                     int& elem_size,
+                                     int& file_size,
+                                     mhdf_TagDataType& file_type,
+                                     hid_t& hdf_type )
 {
+  MBErrorCode rval;
+  MBTag type_handle;
+  std::string tag_name, tag_type_name;
+   
+    // We return NULL for hdf_type if it can be determined from
+    // the file_type.  The only case where it is non-zero is
+    // if the user specified a specific type via a mesh tag.
+  hdf_type = (hid_t)0;
+  
+  rval = iFace->tag_get_data_type( tag, moab_type ); CHK_MB_ERR_0(rval);
+  rval = iFace->tag_get_size( tag, num_bytes );     
+  if (MB_VARIABLE_DATA_LENGTH == rval)
+    num_bytes = MB_VARIABLE_LENGTH;
+  else if (MB_SUCCESS != rval)
+    return rval;
+
+  switch (moab_type)
+  {
+  case MB_TYPE_INTEGER:
+    elem_size = sizeof(int);
+    file_type = mhdf_INTEGER;
+    break;
+  case MB_TYPE_DOUBLE:
+    elem_size = sizeof(double);
+    file_type = mhdf_FLOAT;
+    break;
+  case MB_TYPE_BIT:
+    elem_size = sizeof(bool);
+    file_type = mhdf_BOOLEAN;
+    break;
+  case MB_TYPE_HANDLE:
+    elem_size = sizeof(MBEntityHandle);
+    file_type = mhdf_ENTITY_ID;
+    break;
+  case MB_TYPE_OPAQUE:
+  default:
+    file_type = mhdf_OPAQUE;
+
+    rval = iFace->tag_get_name( tag, tag_name ); CHK_MB_ERR_0(rval);
+    tag_type_name = "__hdf5_tag_type_";
+    tag_type_name += tag_name;
+    rval = iFace->tag_get_handle( tag_type_name.c_str(), type_handle );
+    if (MB_TAG_NOT_FOUND == rval) {
+      elem_size = 1;
+    }
+    else if (MB_SUCCESS == rval) {
+      int hsize;
+      rval = iFace->tag_get_size( type_handle, hsize );
+      if (hsize != sizeof(hid_t))
+        return MB_FAILURE;
+      
+      rval = iFace->tag_get_data( type_handle, 0, 0, &hdf_type );
+      if (rval != MB_SUCCESS)
+        return rval;
+        
+      elem_size = H5Tget_size(hdf_type);
+      if (elem_size != num_bytes)
+        return MB_FAILURE;
+    }
+    else {
+      return rval;
+    }
+  }
+  
+  if (num_bytes == MB_VARIABLE_LENGTH) {
+    file_size = MB_VARIABLE_LENGTH;
+  }
+  else {
+    if (0 != (num_bytes % elem_size))
+      return MB_FAILURE;
+    file_size = num_bytes / elem_size;
+  }
+  
+  return MB_SUCCESS;
+}
+
+MBErrorCode WriteHDF5::get_tag_data_length( const SparseTag& tag_info, unsigned long& result )
+{
+  MBErrorCode rval;
+  result = 0;
+  
+    // split buffer into two pieces, one for pointers and one for sizes
+  size_t step, remaining;
+  step = bufferSize / (sizeof(int) + sizeof(void*));
+  const void** ptr_buffer = reinterpret_cast<const void**>(dataBuffer);
+  int* size_buffer = reinterpret_cast<int*>(ptr_buffer + step); 
+  MBRange subrange;
+  MBRange::const_iterator iter = tag_info.range.begin();
+  for (remaining = tag_info.range.size(); remaining >= step; remaining -= step) {
+      // get subset of range containing 'count' entities
+    MBRange::const_iterator end = iter; end += step;
+    subrange.clear();
+    subrange.merge( iter, end );
+    iter = end;
+      // get tag sizes for entities
+    rval = iFace->tag_get_data( tag_info.tag_id, subrange, ptr_buffer, size_buffer );
+    if (MB_SUCCESS != rval)
+      return rval;
+      // sum lengths
+    for (size_t i = 0; i < step; ++i)
+      result += size_buffer[i];
+  }
+    // process remaining
+  subrange.clear();
+  subrange.merge( iter, tag_info.range.end() );
+  assert( subrange.size() == remaining );
+  rval = iFace->tag_get_data( tag_info.tag_id, subrange, ptr_buffer, size_buffer );
+  if (MB_SUCCESS != rval)
+    return rval;
+  for (size_t i= 0; i < remaining; ++i)
+    result += size_buffer[i];
+  return MB_SUCCESS;
+}
+    
+                                     
+
+MBErrorCode WriteHDF5::create_tag( const SparseTag& tag_info )
+{
+  MBTag tag_id = tag_info.tag_id;
+  unsigned long num_sparse_entities = tag_info.range.size();
   MBTagType storage;
   MBDataType mb_type;
-  MBTag type_handle;
   mhdf_TagDataType mhdf_type;
-  int tag_size, elem_size = 0, mhdf_size;
+  int tag_size, elem_size, mhdf_size;
   hid_t hdf_type = (hid_t)0;
   hid_t handles[2];
-  std::string tag_name, tag_type_name = "__hdf5_tag_type_";
+  std::string tag_name;
   MBErrorCode rval;
   mhdf_Status status;
   
 
     // get tag properties
   rval = iFace->tag_get_type( tag_id, storage  ); CHK_MB_ERR_0(rval);
-  rval = iFace->tag_get_size( tag_id, tag_size ); CHK_MB_ERR_0(rval);
   rval = iFace->tag_get_name( tag_id, tag_name ); CHK_MB_ERR_0(rval);
-  rval = iFace->tag_get_data_type( tag_id, mb_type ); CHK_MB_ERR_0(rval);
+  rval = get_tag_size( tag_id, mb_type, tag_size, elem_size, mhdf_size, mhdf_type, hdf_type );
+  CHK_MB_ERR_0(rval);
   
-  
-    // get type-specific parameters
-  if (MB_TAG_BIT == storage)
-  {
-    mhdf_type = mhdf_BITFIELD;
+    // get default value
+  const void *def_value, *mesh_value;
+  int def_val_len, mesh_val_len;
+  rval = iFace->tag_get_default_value( tag_id, def_value, def_val_len );
+  if (MB_ENTITY_NOT_FOUND == rval) {
+    def_value = 0;
+    def_val_len = 0;
   }
-  else 
-  {
-    switch (mb_type)
-    {
-    case MB_TYPE_INTEGER:
-      elem_size = sizeof(int);
-      mhdf_type = mhdf_INTEGER;
-      break;
-    case MB_TYPE_DOUBLE:
-      elem_size = sizeof(double);
-      mhdf_type = mhdf_FLOAT;
-      break;
-    case MB_TYPE_BIT:
-      elem_size = sizeof(bool);
-      mhdf_type = mhdf_BOOLEAN;
-      break;
-    case MB_TYPE_HANDLE:
-      elem_size = sizeof(MBEntityHandle);
-      mhdf_type = mhdf_ENTITY_ID;
-      break;
-    case MB_TYPE_OPAQUE:
-    default:
-      mhdf_type = mhdf_OPAQUE;
-      
-      tag_type_name = "__hdf5_tag_type_";
-      tag_type_name += tag_name;
-      rval = iFace->tag_get_handle( tag_type_name.c_str(), type_handle );
-      if (MB_SUCCESS == rval)
-      {
-        rval = iFace->tag_get_data( type_handle, 0, 0, &hdf_type );
-        if (rval != MB_SUCCESS || H5Tget_size(hdf_type) != (unsigned)tag_size) 
-          return MB_FAILURE;
-       }
-      else if(MB_TAG_NOT_FOUND != rval)
-        return rval;
-    }
-  }
+  else if (MB_SUCCESS != rval)
+    return rval;
     
-    // if a basic type, check if it is an array of them
-  if (elem_size)
-  {
-    if (tag_size % elem_size)  // tag_size must be a multiple of elem_size
-      return MB_FAILURE;
-    mhdf_size = tag_size / elem_size;
+    // get mesh value
+  rval = iFace->tag_get_data( tag_id, 0, 0, &mesh_value, &mesh_val_len );
+  if (MB_TAG_NOT_FOUND == rval) {
+    mesh_value = 0;
+    mesh_val_len = 0;
   }
-  else
-  {
-    mhdf_size = tag_size;
+  else if (MB_SUCCESS != rval)
+    return rval;
+ 
+    // for variable-length tags, need to calculate total data table size
+  unsigned long data_table_size = 0;
+  if (tag_size == MB_VARIABLE_LENGTH) {
+    rval = get_tag_data_length( tag_info, data_table_size ); 
+    CHK_MB_ERR_0(rval);
   }
   
-  
-    // check for default and global/mesh values
-  assert( 2*tag_size + sizeof(long) < (unsigned long)bufferSize );
- 
-  bool have_default = false;
-  rval = iFace->tag_get_default_value( tag_id, dataBuffer );
-  if (MB_SUCCESS == rval) {
-    have_default = true;
-    if (mb_type == MB_TYPE_HANDLE) 
-      have_default = convert_handle_tag( iFace, idTag, dataBuffer, mhdf_size );
-  }
-  else if(MB_ENTITY_NOT_FOUND != rval)
-    return rval;
+    // for handle-type tags, need to convert from handles to file ids
+  if (MB_TYPE_HANDLE == mb_type) {
+      // make sure there's room in the buffer for both
+    assert( (def_val_len + mesh_val_len) * sizeof(long) < (size_t)bufferSize );
 
-  bool have_global = false;
-  rval = iFace->tag_get_data( tag_id, 0, 0, dataBuffer + tag_size );
-  if (MB_SUCCESS == rval) {
-    have_global = true;
-    if (mb_type == MB_TYPE_HANDLE) 
-      have_default = convert_handle_tag( iFace, idTag, dataBuffer+tag_size, mhdf_size );
+      // convert default value
+    if (def_value) {
+      memcpy( dataBuffer, def_value, def_val_len );
+      if (convert_handle_tag( iFace, idTag, dataBuffer, def_val_len / sizeof(MBEntityHandle) ))
+        def_value = dataBuffer;
+      else
+        def_value = 0;
+    }
+    
+      // convert mesh value
+    if (mesh_value) {
+      MBEntityHandle* ptr = reinterpret_cast<MBEntityHandle*>(dataBuffer + def_val_len);
+      memcpy( ptr, mesh_value, mesh_val_len );
+      if (convert_handle_tag( iFace, idTag, ptr, mesh_val_len / sizeof(MBEntityHandle) ))
+        mesh_value = ptr;
+      else
+        mesh_value = 0;
+    }
   }
-  else if(MB_TAG_NOT_FOUND != rval)
-    return rval;
+     
+ 
+  if (MB_VARIABLE_LENGTH != tag_size) {
+      // write the tag description to the file
+    mhdf_createTag( filePtr,
+                    tag_name.c_str(),
+                    mhdf_type,
+                    mhdf_size,
+                    storage,
+                    def_value,
+                    mesh_value,
+                    hdf_type,
+                    &status );
+    CHK_MHDF_ERR_0(status);
 
 
-    // write the tag description to the file
-  mhdf_createTag( filePtr,
-                  tag_name.c_str(),
-                  mhdf_type,
-                  mhdf_size,
-                  storage,
-                  have_default ? dataBuffer : 0,
-                  have_global ? dataBuffer + tag_size : 0,
-                  hdf_type,
-                  &status );
-  CHK_MHDF_ERR_0(status);
-
-  
-    // create empty table for tag data
-  if (num_sparse_entities)
-  {
-    mhdf_createSparseTagData( filePtr, 
-                              tag_name.c_str(), 
-                              num_sparse_entities,
-                              handles,
-                              &status );
+      // create empty table for tag data
+    if (num_sparse_entities)
+    {
+      mhdf_createSparseTagData( filePtr, 
+                                tag_name.c_str(), 
+                                num_sparse_entities,
+                                handles,
+                                &status );
+      CHK_MHDF_ERR_0(status);
+      mhdf_closeData( filePtr, handles[0], &status );
+      mhdf_closeData( filePtr, handles[1], &status );
+    }
+  }
+  else {
+    mhdf_createVarLenTag( filePtr,
+                          tag_name.c_str(),
+                          mhdf_type,
+                          storage,
+                          def_value, def_val_len / elem_size,
+                          mesh_value, mesh_val_len / elem_size,
+                          hdf_type,
+                          &status );
     CHK_MHDF_ERR_0(status);
-    mhdf_closeData( filePtr, handles[0], &status );
-    mhdf_closeData( filePtr, handles[1], &status );
+    
+      // create empty table for tag data
+    if (num_sparse_entities) {
+      mhdf_createVarLenTagData( filePtr, 
+                                tag_name.c_str(),
+                                num_sparse_entities,
+                                data_table_size / elem_size,
+                                handles,
+                                &status );
+      CHK_MHDF_ERR_0(status);
+      mhdf_closeData( filePtr, handles[0], &status );
+      mhdf_closeData( filePtr, handles[1], &status );
+      mhdf_closeData( filePtr, handles[2], &status );
+    }
   }
-  
+    
   return MB_SUCCESS;
 }

Modified: MOAB/trunk/WriteHDF5.hpp
===================================================================
--- MOAB/trunk/WriteHDF5.hpp	2008-02-06 01:00:42 UTC (rev 1588)
+++ MOAB/trunk/WriteHDF5.hpp	2008-02-06 01:01:31 UTC (rev 1589)
@@ -139,13 +139,6 @@
                                  long children_length,
                                  long parents_length );
 
-  /** Helper function for create-file
-   *
-   * Write tag meta-info and create zero-ed table where
-   * tag values will be written.
-   */
-  MBErrorCode create_tag( MBTag tag_id, id_t num_sparse_entities );
-
   //! Write exodus-type QA info
   MBErrorCode write_qa( std::vector<std::string>& list );
 
@@ -186,8 +179,12 @@
     //! The list of entities with this tag
     MBRange range;
     //! The offset at which to begin writting this processor's data.
-    //! Always zero except for parallel IO.
+    //! Always zero except for parallel IO. 
     id_t offset;
+    //! For variable-length tags, a second offset for the tag data table,
+    //! separate from the offset used for the ID and Index tables.
+    //! Always zero except for parallel IO. 
+    id_t varDataOffset;
     //! Write tag data (for serial, is always equal to !range.empty())
     bool write;
     
@@ -252,6 +249,13 @@
                             unsigned long& flags );
 
 protected:
+
+  /** Helper function for create-file
+   *
+   * Write tag meta-info and create zero-ed table where
+   * tag values will be written.
+   */
+  MBErrorCode create_tag( const SparseTag& tag_info );
   
   /** Get possibly compacted list of IDs for passed entities
    *
@@ -355,6 +359,38 @@
                                 MBRange::const_iterator end,
                                 int nodes_per_element,
                                 id_t* id_data_out );
+                                
+  //! get sum of lengths of tag values (in bytes) for 
+  //! variable length tag data.
+  MBErrorCode get_tag_data_length( const SparseTag& tag_info,
+                                   unsigned long& result );
+                                   
+  //! Get size data for tag
+  //!\param tag       MOAB tag ID
+  //!\param moab_type Output: MBDataType for tag
+  //!\param num_bytes Output: MOAB tag size (bits for bit tags).
+  //!                         MB_VARIABLE_LENGTH for variable-length tags.
+  //!\param elem_size Output: Size of type values per entity (e.g.
+  //!                         sizeof(double) for MB_TYPE_DOUBLE data)
+  //!                         One for bit and opaque tags.
+  //!\param file_size Output: num_bytes/elem_size
+  //!\param file_type Output: mhdf type enumeration
+  //!\param hdf_type  Output: zero or handle for user-defined custom type
+  //!                         (user-defined type available only for opaque
+  //!                         data.)
+  MBErrorCode get_tag_size( MBTag tag,
+                            MBDataType& moab_type,
+                            int& num_bytes,
+                            int& elem_size,
+                            int& file_size,
+                            mhdf_TagDataType& file_type,
+                            hid_t& hdf_type );
+                            
+  //! Write ID table for sparse tag
+  MBErrorCode write_sparse_ids( const SparseTag& tag_data, hid_t table_handle );
+  
+  //! Write varialbe-length tag data
+  MBErrorCode write_var_len_tag( const SparseTag& tag_info );
 };
 
 #endif




More information about the moab-dev mailing list