Loading [MathJax]/extensions/tex2jax.js
Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
WriteHDF5.cpp
Go to the documentation of this file.
1 /** 2  * MOAB, a Mesh-Oriented datABase, is a software component for creating, 3  * storing and accessing finite element mesh data. 4  * 5  * Copyright 2004 Sandia Corporation. Under the terms of Contract 6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 7  * retains certain rights in this software. 8  * 9  * This library is free software; you can redistribute it and/or 10  * modify it under the terms of the GNU Lesser General Public 11  * License as published by the Free Software Foundation; either 12  * version 2.1 of the License, or (at your option) any later version. 13  * 14  */ 15  16 //------------------------------------------------------------------------- 17 // Filename : WriteHDF5.cpp 18 // 19 // Purpose : TSTT HDF5 Writer 20 // 21 // Special Notes : WriteSLAC used as template for this 22 // 23 // Creator : Jason Kraftcheck 24 // 25 // Creation Date : 04/01/04 26 //------------------------------------------------------------------------- 27  28 #include <cassert> 29 #if defined( _MSC_VER ) 30 typedef int id_t; 31 #elif defined( __MINGW32__ ) 32 #include <sys/time.h> 33 #else 34 #include <ctime> 35 #endif 36  37 #include <cstdlib> 38 #include <cstring> 39 #include <cstdarg> 40 #include <limits> 41 #include <cstdio> 42 #include <iostream> 43 #include "WriteHDF5.hpp" 44 #include <H5Tpublic.h> 45 #include <H5Ppublic.h> 46 #include <H5Epublic.h> 47 #include "moab/Interface.hpp" 48 #include "Internals.hpp" 49 #include "MBTagConventions.hpp" 50 #include "moab/CN.hpp" 51 #include "moab/FileOptions.hpp" 52 #include "moab/CpuTimer.hpp" 53 #include "IODebugTrack.hpp" 54 #include "mhdf.h" 55  56 #ifndef MOAB_HAVE_HDF5 57 #error Attempt to compile WriteHDF5 with HDF5 support disabled 58 #endif 59  60 #undef BLOCKED_COORD_IO 61  62 #ifdef MOAB_HAVE_VALGRIND 63 #include <valgrind/memcheck.h> 64  65 template < typename T > 66 inline void VALGRIND_MAKE_VEC_UNDEFINED( std::vector< T >& v ) 67 { 68  (void)VALGRIND_MAKE_MEM_UNDEFINED( (T*)&v[0], v.size() * sizeof( T ) ); 69 } 70  71 #else 72 #ifndef VALGRIND_CHECK_MEM_IS_DEFINED 73 #define VALGRIND_CHECK_MEM_IS_DEFINED( a, b ) ( (void)0 ) 74 #endif 75 #ifndef VALGRIND_CHECK_MEM_IS_ADDRESSABLE 76 #define VALGRIND_CHECK_MEM_IS_ADDRESSABLE( a, b ) ( (void)0 ) 77 #endif 78 #ifndef VALGRIND_MAKE_MEM_UNDEFINED 79 #define VALGRIND_MAKE_MEM_UNDEFINED( a, b ) ( (void)0 ) 80 #endif 81  82 template < typename T > 83 inline void VALGRIND_MAKE_VEC_UNDEFINED( std::vector< T >& ) 84 { 85  (void)VALGRIND_MAKE_MEM_UNDEFINED( 0, 0 ); 86 } 87  88 #endif 89  90 namespace moab 91 { 92  93 #define WRITE_HDF5_BUFFER_SIZE ( 40 * 1024 * 1024 ) 94  95 static hid_t get_id_type() 96 { 97  if( 8 == sizeof( WriteHDF5::wid_t ) ) 98  { 99  if( 8 == sizeof( long ) ) 100  return H5T_NATIVE_ULONG; 101  else 102  return H5T_NATIVE_UINT64; 103  } 104  else if( 4 == sizeof( WriteHDF5::wid_t ) ) 105  { 106  if( 4 == sizeof( int ) ) 107  return H5T_NATIVE_UINT; 108  else 109  return H5T_NATIVE_UINT32; 110  } 111  else 112  { 113  assert( 0 ); 114  return (hid_t)-1; 115  } 116 } 117  118 // This is the HDF5 type used to store file IDs 119 const hid_t WriteHDF5::id_type = get_id_type(); 120  121 // This function doesn't do anything useful. It's just a nice 122 // place to set a break point to determine why the writer fails. 123 static inline ErrorCode error( ErrorCode rval ) 124 { 125  return rval; 126 } 127  128 // Call \c error function during HDF5 library errors to make 129 // it easier to trap such errors in the debugger. This function 130 // gets registered with the HDF5 library as a callback. It 131 // works the same as the default (H5Eprint), except that it 132 // also calls the \c error function as a no-op. 133 #if defined( H5E_auto_t_vers ) && H5E_auto_t_vers > 1 134 static herr_t handle_hdf5_error( hid_t stack, void* data ) 135 { 136  WriteHDF5::HDF5ErrorHandler* h = reinterpret_cast< WriteHDF5::HDF5ErrorHandler* >( data ); 137  herr_t result = 0; 138  if( h->func ) result = ( *h->func )( stack, h->data ); 139  error( MB_FAILURE ); 140  return result; 141 } 142 #else 143 static herr_t handle_hdf5_error( void* data ) 144 { 145  WriteHDF5::HDF5ErrorHandler* h = reinterpret_cast< WriteHDF5::HDF5ErrorHandler* >( data ); 146  herr_t result = 0; 147  if( h->func ) result = ( *h->func )( h->data ); 148  error( MB_FAILURE ); 149  return result; 150 } 151 #endif 152  153 // Some macros to handle error checking. The 154 // CHK_MHDF__ERR* macros check the value of an mhdf_Status 155 // object. The CHK_MB_ERR_* check the value of an ErrorCode. 156 // The *_0 macros accept no other arguments. The *_1 157 // macros accept a single hdf5 handle to close on error. 158 // The *_2 macros accept an array of two hdf5 handles to 159 // close on error. The _*2C macros accept one hdf5 handle 160 // to close on error and a bool and an hdf5 handle where 161 // the latter handle is conditionally closed depending on 162 // the value of the bool. All macros contain a "return" 163 // statement. 164 #define CHK_MHDF_ERR_0( A ) \ 165  do \ 166  { \ 167  if( mhdf_isError( &( A ) ) ) \ 168  { \ 169  MB_SET_ERR_CONT( mhdf_message( &( A ) ) ); \ 170  assert( 0 ); \ 171  return error( MB_FAILURE ); \ 172  } \ 173  } while( false ) 174  175 #define CHK_MHDF_ERR_1( A, B ) \ 176  do \ 177  { \ 178  if( mhdf_isError( &( A ) ) ) \ 179  { \ 180  MB_SET_ERR_CONT( mhdf_message( &( A ) ) ); \ 181  assert( 0 ); \ 182  mhdf_closeData( filePtr, ( B ), &( A ) ); \ 183  return error( MB_FAILURE ); \ 184  } \ 185  } while( false ) 186  187 #define CHK_MHDF_ERR_2( A, B ) \ 188  do \ 189  { \ 190  if( mhdf_isError( &( A ) ) ) \ 191  { \ 192  MB_SET_ERR_CONT( mhdf_message( &( A ) ) ); \ 193  assert( 0 ); \ 194  mhdf_closeData( filePtr, ( B )[0], &( A ) ); \ 195  mhdf_closeData( filePtr, ( B )[1], &( A ) ); \ 196  return error( MB_FAILURE ); \ 197  } \ 198  } while( false ) 199  200 #define CHK_MHDF_ERR_3( A, B ) \ 201  do \ 202  { \ 203  if( mhdf_isError( &( A ) ) ) \ 204  { \ 205  MB_SET_ERR_CONT( mhdf_message( &( A ) ) ); \ 206  assert( 0 ); \ 207  mhdf_closeData( filePtr, ( B )[0], &( A ) ); \ 208  mhdf_closeData( filePtr, ( B )[1], &( A ) ); \ 209  mhdf_closeData( filePtr, ( B )[2], &( A ) ); \ 210  return error( MB_FAILURE ); \ 211  } \ 212  } while( false ) 213  214 #define CHK_MHDF_ERR_2C( A, B, C, D ) \ 215  do \ 216  { \ 217  if( mhdf_isError( &( A ) ) ) \ 218  { \ 219  MB_SET_ERR_CONT( mhdf_message( &( A ) ) ); \ 220  assert( 0 ); \ 221  mhdf_closeData( filePtr, ( B ), &( A ) ); \ 222  if( C ) mhdf_closeData( filePtr, ( D ), &( A ) ); \ 223  return error( MB_FAILURE ); \ 224  } \ 225  } while( false ) 226  227 #define CHK_MB_ERR_0( A ) \ 228  do \ 229  { \ 230  if( MB_SUCCESS != ( A ) ) \ 231  { \ 232  MB_CHK_ERR_CONT( ( A ) ); \ 233  return error( A ); \ 234  } \ 235  } while( false ) 236  237 #define CHK_MB_ERR_1( A, B, C ) \ 238  do \ 239  { \ 240  if( MB_SUCCESS != ( A ) ) \ 241  { \ 242  MB_CHK_ERR_CONT( ( A ) ); \ 243  mhdf_closeData( filePtr, ( B ), &( C ) ); \ 244  assert( 0 ); \ 245  return error( A ); \ 246  } \ 247  } while( false ) 248  249 #define CHK_MB_ERR_2( A, B, C ) \ 250  do \ 251  { \ 252  if( MB_SUCCESS != ( A ) ) \ 253  { \ 254  MB_CHK_ERR_CONT( ( A ) ); \ 255  mhdf_closeData( filePtr, ( B )[0], &( C ) ); \ 256  mhdf_closeData( filePtr, ( B )[1], &( C ) ); \ 257  write_finished(); \ 258  assert( 0 ); \ 259  return error( A ); \ 260  } \ 261  } while( false ) 262  263 #define CHK_MB_ERR_3( A, B, C ) \ 264  do \ 265  { \ 266  if( MB_SUCCESS != ( A ) ) \ 267  { \ 268  MB_CHK_ERR_CONT( ( A ) ); \ 269  mhdf_closeData( filePtr, ( B )[0], &( C ) ); \ 270  mhdf_closeData( filePtr, ( B )[1], &( C ) ); \ 271  mhdf_closeData( filePtr, ( B )[2], &( C ) ); \ 272  write_finished(); \ 273  assert( 0 ); \ 274  return error( A ); \ 275  } \ 276  } while( false ) 277  278 #define CHK_MB_ERR_2C( A, B, C, D, E ) \ 279  do \ 280  { \ 281  if( MB_SUCCESS != ( A ) ) \ 282  { \ 283  MB_CHK_ERR_CONT( ( A ) ); \ 284  mhdf_closeData( filePtr, ( B ), &( E ) ); \ 285  if( C ) mhdf_closeData( filePtr, ( D ), &( E ) ); \ 286  write_finished(); \ 287  assert( 0 ); \ 288  return error( A ); \ 289  } \ 290  } while( false ) 291  292 #define debug_barrier() debug_barrier_line( __LINE__ ) 293 void WriteHDF5::debug_barrier_line( int ) {} 294  295 class CheckOpenWriteHDF5Handles 296 { 297  int fileline; 298  mhdf_FileHandle handle; 299  int enter_count; 300  301  public: 302  CheckOpenWriteHDF5Handles( mhdf_FileHandle file, int line ) 303  : fileline( line ), handle( file ), enter_count( mhdf_countOpenHandles( file ) ) 304  { 305  } 306  307  ~CheckOpenWriteHDF5Handles() 308  { 309  int new_count = mhdf_countOpenHandles( handle ); 310  if( new_count != enter_count ) 311  { 312  std::cout << "Leaked HDF5 object handle in function at " << __FILE__ << ":" << fileline << std::endl 313  << "Open at entrance: " << enter_count << std::endl 314  << "Open at exit: " << new_count << std::endl; 315  } 316  } 317 }; 318  319 MPEState WriteHDF5::topState; 320 MPEState WriteHDF5::subState; 321  322 #ifdef NDEBUG 323 #define CHECK_OPEN_HANDLES 324 #else 325 #define CHECK_OPEN_HANDLES CheckOpenWriteHDF5Handles check_open_handles_( filePtr, __LINE__ ) 326 #endif 327  328 bool WriteHDF5::convert_handle_tag( const EntityHandle* source, EntityHandle* dest, size_t count ) const 329 { 330  bool some_valid = false; 331  for( size_t i = 0; i < count; ++i ) 332  { 333  if( !source[i] ) 334  dest[i] = 0; 335  else 336  { 337  dest[i] = idMap.find( source[i] ); 338  if( dest[i] ) some_valid = true; 339  } 340  } 341  342  return some_valid; 343 } 344  345 bool WriteHDF5::convert_handle_tag( EntityHandle* data, size_t count ) const 346 { 347  assert( sizeof( EntityHandle ) == sizeof( wid_t ) ); 348  return convert_handle_tag( data, data, count ); 349 } 350  351 ErrorCode WriteHDF5::assign_ids( const Range& entities, wid_t id ) 352 { 353  Range::const_pair_iterator pi; 354  for( pi = entities.const_pair_begin(); pi != entities.const_pair_end(); ++pi ) 355  { 356  const EntityHandle n = pi->second - pi->first + 1; 357  dbgOut.printf( 3, "Assigning %s %lu to %lu to file IDs [%lu,%lu]\n", 358  CN::EntityTypeName( TYPE_FROM_HANDLE( pi->first ) ), 359  (unsigned long)( ID_FROM_HANDLE( pi->first ) ), 360  (unsigned long)( ID_FROM_HANDLE( pi->first ) + n - 1 ), (unsigned long)id, 361  (unsigned long)( id + n - 1 ) ); 362  if( TYPE_FROM_HANDLE( pi->first ) == MBPOLYGON || TYPE_FROM_HANDLE( pi->first ) == MBPOLYHEDRON ) 363  { 364  int num_vertices = 0; 365  const EntityHandle* conn = 0; 366  iFace->get_connectivity( pi->first, conn, num_vertices ); 367  dbgOut.printf( 3, " poly with %d verts/faces \n", num_vertices ); 368  } 369  if( !idMap.insert( pi->first, id, n ).second ) return error( MB_FAILURE ); 370  id += n; 371  } 372  373  return MB_SUCCESS; 374 } 375  376 const char* WriteHDF5::ExportSet::name() const 377 { 378  static char buffer[128]; 379  switch( type ) 380  { 381  case MBVERTEX: 382  return mhdf_node_type_handle(); 383  case MBENTITYSET: 384  return mhdf_set_type_handle(); 385  default: 386  snprintf( buffer, 128, "%s%d", CN::EntityTypeName( type ), num_nodes ); 387  return buffer; 388  } 389 } 390  391 WriterIface* WriteHDF5::factory( Interface* iface ) 392 { 393  return new WriteHDF5( iface ); 394 } 395  396 WriteHDF5::WriteHDF5( Interface* iface ) 397  : bufferSize( WRITE_HDF5_BUFFER_SIZE ), dataBuffer( 0 ), iFace( iface ), writeUtil( 0 ), filePtr( 0 ), 398  setContentsOffset( 0 ), setChildrenOffset( 0 ), setParentsOffset( 0 ), maxNumSetContents( 0 ), 399  maxNumSetChildren( 0 ), maxNumSetParents( 0 ), writeSets( false ), writeSetContents( false ), 400  writeSetChildren( false ), writeSetParents( false ), parallelWrite( false ), collectiveIO( false ), 401  writeTagDense( false ), writeProp( H5P_DEFAULT ), dbgOut( "H5M", stderr ), debugTrack( false ) 402 { 403 } 404  405 ErrorCode WriteHDF5::init() 406 { 407  ErrorCode rval; 408  409  if( writeUtil ) // init has already been called 410  return MB_SUCCESS; 411  /* 412  #ifdef DEBUG 413  H5Eset_auto(&hdf_error_handler, writeUtil); // HDF5 callback for errors 414  #endif 415  */ 416  // For known tag types, store the corresponding HDF5 in which 417  // the tag data is to be written in the file. 418  // register_known_tag_types(iFace); 419  420  // Get the util interface 421  rval = iFace->query_interface( writeUtil ); 422  CHK_MB_ERR_0( rval ); 423  424  idMap.clear(); 425  426 #if defined( H5Eget_auto_vers ) && H5Eget_auto_vers > 1 427  herr_t err = H5Eget_auto( H5E_DEFAULT, &errorHandler.func, &errorHandler.data ); 428 #else 429  herr_t err = H5Eget_auto( &errorHandler.func, &errorHandler.data ); 430 #endif 431  if( err < 0 ) 432  { 433  errorHandler.func = 0; 434  errorHandler.data = 0; 435  } 436  else 437  { 438 #if defined( H5Eset_auto_vers ) && H5Eset_auto_vers > 1 439  err = H5Eset_auto( H5E_DEFAULT, &handle_hdf5_error, &errorHandler ); 440 #else 441  err = H5Eset_auto( &handle_hdf5_error, &errorHandler ); 442 #endif 443  if( err < 0 ) 444  { 445  errorHandler.func = 0; 446  errorHandler.data = 0; 447  } 448  } 449  450  if( !topState.valid() ) topState = MPEState( "WriteHDF5", "yellow" ); 451  if( !subState.valid() ) subState = MPEState( "WriteHDF5 subevent", "cyan" ); 452  453  return MB_SUCCESS; 454 } 455  456 ErrorCode WriteHDF5::write_finished() 457 { 458  // Release memory allocated in lists 459  exportList.clear(); 460  nodeSet.range.clear(); 461  setSet.range.clear(); 462  tagList.clear(); 463  idMap.clear(); 464  465  HDF5ErrorHandler handler; 466 #if defined( H5Eget_auto_vers ) && H5Eget_auto_vers > 1 467  herr_t err = H5Eget_auto( H5E_DEFAULT, &handler.func, &handler.data ); 468 #else 469  herr_t err = H5Eget_auto( &handler.func, &handler.data ); 470 #endif 471  if( err >= 0 && handler.func == &handle_hdf5_error ) 472  { 473  assert( handler.data == &errorHandler ); 474 #if defined( H5Eget_auto_vers ) && H5Eget_auto_vers > 1 475  H5Eset_auto( H5E_DEFAULT, errorHandler.func, errorHandler.data ); 476 #else 477  H5Eset_auto( errorHandler.func, errorHandler.data ); 478 #endif 479  } 480  481  return MB_SUCCESS; 482 } 483  484 WriteHDF5::~WriteHDF5() 485 { 486  if( !writeUtil ) // init() failed. 487  return; 488  489  iFace->release_interface( writeUtil ); 490 } 491  492 ErrorCode WriteHDF5::write_file( const char* filename, 493  bool overwrite, 494  const FileOptions& opts, 495  const EntityHandle* set_array, 496  const int num_sets, 497  const std::vector< std::string >& qa_records, 498  const Tag* tag_list, 499  int num_tags, 500  int user_dimension ) 501 { 502  mhdf_Status status; 503  504  parallelWrite = false; 505  collectiveIO = false; 506  507  // Enable debug output 508  int tmpval = 0; 509  if( MB_SUCCESS == opts.get_int_option( "DEBUG_IO", 1, tmpval ) ) dbgOut.set_verbosity( tmpval ); 510  511  // writeTagDense = (MB_SUCCESS == opts.get_null_option("DENSE_TAGS")); 512  writeTagDense = true; 513  514  // Enable some extra checks for reads. Note: amongst other things this 515  // will print errors if the entire file is not read, so if doing a 516  // partial read that is not a parallel read, this should be disabled. 517  debugTrack = ( MB_SUCCESS == opts.get_null_option( "DEBUG_BINIO" ) ); 518  519  bufferSize = WRITE_HDF5_BUFFER_SIZE; 520  int buf_size; 521  ErrorCode rval = opts.get_int_option( "BUFFER_SIZE", buf_size ); 522  if( MB_SUCCESS == rval && buf_size >= 24 ) bufferSize = buf_size; 523  524  // Allocate internal buffer to use when gathering data to write. 525  dataBuffer = (char*)malloc( bufferSize ); 526  if( !dataBuffer ) return error( MB_MEMORY_ALLOCATION_FAILED ); 527  528  // Clear filePtr so we know if it is open upon failure 529  filePtr = 0; 530  531  // Do actual write. 532  writeProp = H5P_DEFAULT; 533  ErrorCode result = write_file_impl( filename, overwrite, opts, set_array, num_sets, qa_records, tag_list, num_tags, 534  user_dimension ); 535  // Close writeProp if it was opened 536  if( writeProp != H5P_DEFAULT ) H5Pclose( writeProp ); 537  538  // Free memory buffer 539  free( dataBuffer ); 540  dataBuffer = 0; 541  542  // Close file 543  bool created_file = false; 544  if( filePtr ) 545  { 546  created_file = true; 547  mhdf_closeFile( filePtr, &status ); 548  filePtr = 0; 549  if( mhdf_isError( &status ) ) 550  { 551  MB_SET_ERR_CONT( mhdf_message( &status ) ); 552  if( MB_SUCCESS == result ) result = MB_FAILURE; 553  } 554  } 555  556  // Release other resources 557  if( MB_SUCCESS == result ) 558  result = write_finished(); 559  else 560  write_finished(); 561  562  // If write failed, remove file unless KEEP option was specified 563  if( MB_SUCCESS != result && created_file && MB_ENTITY_NOT_FOUND == opts.get_null_option( "KEEP" ) ) 564  remove( filename ); 565  566  return result; 567 } 568  569 ErrorCode WriteHDF5::write_file_impl( const char* filename, 570  bool overwrite, 571  const FileOptions& opts, 572  const EntityHandle* set_array, 573  const int num_sets, 574  const std::vector< std::string >& qa_records, 575  const Tag* tag_list, 576  int num_tags, 577  int user_dimension ) 578 { 579  ErrorCode result; 580  std::list< TagDesc >::const_iterator t_itor; 581  std::list< ExportSet >::iterator ex_itor; 582  EntityHandle elem_count, max_id; 583  double times[NUM_TIMES] = { 0 }; 584  585  if( MB_SUCCESS != init() ) return error( MB_FAILURE ); 586  587  // See if we need to report times 588  bool cputime = false; 589  result = opts.get_null_option( "CPUTIME" ); 590  if( MB_SUCCESS == result ) cputime = true; 591  592  CpuTimer timer; 593  594  dbgOut.tprint( 1, "Gathering Mesh\n" ); 595  topState.start( "gathering mesh" ); 596  597  // Gather mesh to export 598  exportList.clear(); 599  if( 0 == num_sets || ( 1 == num_sets && set_array[0] == 0 ) ) 600  { 601  result = gather_all_mesh(); 602  topState.end( result ); 603  CHK_MB_ERR_0( result ); 604  } 605  else 606  { 607  std::vector< EntityHandle > passed_export_list( set_array, set_array + num_sets ); 608  result = gather_mesh_info( passed_export_list ); 609  topState.end( result ); 610  CHK_MB_ERR_0( result ); 611  } 612  613  times[GATHER_TIME] = timer.time_elapsed(); 614  615  // if (nodeSet.range.size() == 0) 616  // return error(MB_ENTITY_NOT_FOUND); 617  618  dbgOut.tprint( 1, "Checking ID space\n" ); 619  620  // Make sure ID space is sufficient 621  elem_count = nodeSet.range.size() + setSet.range.size(); 622  for( ex_itor = exportList.begin(); ex_itor != exportList.end(); ++ex_itor ) 623  elem_count += ex_itor->range.size(); 624  max_id = (EntityHandle)1 << ( 8 * sizeof( wid_t ) - 1 ); 625  if( elem_count > max_id ) 626  { 627  MB_SET_ERR_CONT( "ID space insufficient for mesh size" ); 628  return error( result ); 629  } 630  631  dbgOut.tprint( 1, "Creating File\n" ); 632  633  // Figure out the dimension in which to write the mesh. 634  int mesh_dim; 635  result = iFace->get_dimension( mesh_dim ); 636  CHK_MB_ERR_0( result ); 637  638  if( user_dimension < 1 ) user_dimension = mesh_dim; 639  user_dimension = user_dimension > mesh_dim ? mesh_dim : user_dimension; 640  641  // Create the file layout, including all tables (zero-ed) and 642  // all structure and meta information. 643  const char* optnames[] = { "WRITE_PART", "FORMAT", 0 }; 644  int junk; 645  parallelWrite = ( MB_SUCCESS == opts.match_option( "PARALLEL", optnames, junk ) ); 646  if( parallelWrite ) 647  { 648  // Just store Boolean value based on string option here. 649  // parallel_create_file will set writeProp accordingly. 650  // collectiveIO = (MB_SUCCESS == opts.get_null_option("COLLECTIVE")); 651  // dbgOut.printf(2, "'COLLECTIVE' option = %s\n", collectiveIO ? "YES" : "NO"); 652  // Do this all the time, as it appears to be much faster than indep in some cases 653  collectiveIO = true; 654  result = 655  parallel_create_file( filename, overwrite, qa_records, opts, tag_list, num_tags, user_dimension, times ); 656  } 657  else 658  { 659  result = serial_create_file( filename, overwrite, qa_records, tag_list, num_tags, user_dimension ); 660  } 661  if( MB_SUCCESS != result ) return error( result ); 662  663  times[CREATE_TIME] = timer.time_elapsed(); 664  665  dbgOut.tprint( 1, "Writing Nodes.\n" ); 666  // Write node coordinates 667  if( !nodeSet.range.empty() || parallelWrite ) 668  { 669  topState.start( "writing coords" ); 670  result = write_nodes(); 671  topState.end( result ); 672  if( MB_SUCCESS != result ) return error( result ); 673  } 674  675  times[COORD_TIME] = timer.time_elapsed(); 676  677  dbgOut.tprint( 1, "Writing connectivity.\n" ); 678  679  // Write element connectivity 680  for( ex_itor = exportList.begin(); ex_itor != exportList.end(); ++ex_itor ) 681  { 682  topState.start( "writing connectivity for ", ex_itor->name() ); 683  result = write_elems( *ex_itor ); 684  topState.end( result ); 685  if( MB_SUCCESS != result ) return error( result ); 686  } 687  times[CONN_TIME] = timer.time_elapsed(); 688  689  dbgOut.tprint( 1, "Writing sets.\n" ); 690  691  // Write meshsets 692  result = write_sets( times ); 693  if( MB_SUCCESS != result ) return error( result ); 694  debug_barrier(); 695  696  times[SET_TIME] = timer.time_elapsed(); 697  dbgOut.tprint( 1, "Writing adjacencies.\n" ); 698  699  // Write adjacencies 700  // Tim says don't save node adjacencies! 701 #ifdef MB_H5M_WRITE_NODE_ADJACENCIES 702  result = write_adjacencies( nodeSet ); 703  if( MB_SUCCESS != result ) return error( result ); 704 #endif 705  for( ex_itor = exportList.begin(); ex_itor != exportList.end(); ++ex_itor ) 706  { 707  topState.start( "writing adjacencies for ", ex_itor->name() ); 708  result = write_adjacencies( *ex_itor ); 709  topState.end( result ); 710  if( MB_SUCCESS != result ) return error( result ); 711  } 712  times[ADJ_TIME] = timer.time_elapsed(); 713  714  dbgOut.tprint( 1, "Writing tags.\n" ); 715  716  // Write tags 717  for( t_itor = tagList.begin(); t_itor != tagList.end(); ++t_itor ) 718  { 719  std::string name; 720  iFace->tag_get_name( t_itor->tag_id, name ); 721  topState.start( "writing tag: ", name.c_str() ); 722  result = write_tag( *t_itor, times ); 723  topState.end( result ); 724  if( MB_SUCCESS != result ) return error( result ); 725  } 726  times[TAG_TIME] = timer.time_elapsed(); 727  728  times[TOTAL_TIME] = timer.time_since_birth(); 729  730  if( cputime ) 731  { 732  print_times( times ); 733  } 734  735  return MB_SUCCESS; 736 } 737  738 ErrorCode WriteHDF5::initialize_mesh( const Range ranges[5] ) 739 { 740  ErrorCode rval; 741  742  if( !ranges[0].all_of_type( MBVERTEX ) ) return error( MB_FAILURE ); 743  nodeSet.range = ranges[0]; 744  nodeSet.type = MBVERTEX; 745  nodeSet.num_nodes = 1; 746  nodeSet.max_num_ents = nodeSet.max_num_adjs = 0; 747  748  if( !ranges[4].all_of_type( MBENTITYSET ) ) return error( MB_FAILURE ); 749  setSet.range = ranges[4]; 750  setSet.type = MBENTITYSET; 751  setSet.num_nodes = 0; 752  setSet.max_num_ents = setSet.max_num_adjs = 0; 753  maxNumSetContents = maxNumSetChildren = maxNumSetParents = 0; 754  755  exportList.clear(); 756  std::vector< Range > bins( 1024 ); // Sort entities by connectivity length 757  // Resize is expensive due to Range copy, so start big 758  for( EntityType type = MBEDGE; type < MBENTITYSET; ++type ) 759  { 760  ExportSet set; 761  set.max_num_ents = set.max_num_adjs = 0; 762  const int dim = CN::Dimension( type ); 763  764  // Group entities by connectivity length 765  bins.clear(); 766  assert( dim >= 0 && dim <= 4 ); 767  std::pair< Range::const_iterator, Range::const_iterator > p = ranges[dim].equal_range( type ); 768  Range::const_iterator i = p.first; 769  while( i != p.second ) 770  { 771  Range::const_iterator first = i; 772  EntityHandle const* conn; 773  int len, firstlen; 774  775  // Dummy storage vector for structured mesh "get_connectivity" function 776  std::vector< EntityHandle > storage; 777  778  rval = iFace->get_connectivity( *i, conn, firstlen, false, &storage ); 779  if( MB_SUCCESS != rval ) return error( rval ); 780  781  for( ++i; i != p.second; ++i ) 782  { 783  rval = iFace->get_connectivity( *i, conn, len, false, &storage ); 784  if( MB_SUCCESS != rval ) return error( rval ); 785  786  if( len != firstlen ) break; 787  } 788  789  if( firstlen >= (int)bins.size() ) bins.resize( firstlen + 1 ); 790  bins[firstlen].merge( first, i ); 791  } 792  // Create ExportSet for each group 793  for( std::vector< Range >::iterator j = bins.begin(); j != bins.end(); ++j ) 794  { 795  if( j->empty() ) continue; 796  797  set.range.clear(); 798  set.type = type; 799  set.num_nodes = j - bins.begin(); 800  exportList.push_back( set ); 801  exportList.back().range.swap( *j ); 802  } 803  } 804  805  return MB_SUCCESS; 806 } 807  808 // Gather the mesh to be written from a list of owning meshsets. 809 ErrorCode WriteHDF5::gather_mesh_info( const std::vector< EntityHandle >& export_sets ) 810 { 811  ErrorCode rval; 812  813  int dim; 814  Range range; // Temporary storage 815  Range ranges[5]; // Lists of entities to export, grouped by dimension 816  817  // Gather list of all related sets 818  std::vector< EntityHandle > stack( export_sets ); 819  std::copy( export_sets.begin(), export_sets.end(), stack.begin() ); 820  std::vector< EntityHandle > set_children; 821  while( !stack.empty() ) 822  { 823  EntityHandle meshset = stack.back(); 824  stack.pop_back(); 825  ranges[4].insert( meshset ); 826  827  // Get contained sets 828  range.clear(); 829  rval = iFace->get_entities_by_type( meshset, MBENTITYSET, range ); 830  CHK_MB_ERR_0( rval ); 831  for( Range::iterator ritor = range.begin(); ritor != range.end(); ++ritor ) 832  { 833  if( ranges[4].find( *ritor ) == ranges[4].end() ) stack.push_back( *ritor ); 834  } 835  836  // Get child sets 837  set_children.clear(); 838  rval = iFace->get_child_meshsets( meshset, set_children, 1 ); 839  CHK_MB_ERR_0( rval ); 840  for( std::vector< EntityHandle >::iterator vitor = set_children.begin(); vitor != set_children.end(); ++vitor ) 841  { 842  if( ranges[4].find( *vitor ) == ranges[4].end() ) stack.push_back( *vitor ); 843  } 844  } 845  846  // Gather list of all mesh entities from list of sets, 847  // grouped by dimension. 848  for( Range::iterator setitor = ranges[4].begin(); setitor != ranges[4].end(); ++setitor ) 849  { 850  for( dim = 0; dim < 4; ++dim ) 851  { 852  range.clear(); 853  rval = iFace->get_entities_by_dimension( *setitor, dim, range, false ); 854  CHK_MB_ERR_0( rval ); 855  856  ranges[dim].merge( range ); 857  } 858  } 859  860  // For each list of elements, append adjacent children and 861  // nodes to lists. 862  for( dim = 3; dim > 0; --dim ) 863  { 864  for( int cdim = 1; cdim < dim; ++cdim ) 865  { 866  range.clear(); 867  rval = iFace->get_adjacencies( ranges[dim], cdim, false, range ); 868  CHK_MB_ERR_0( rval ); 869  ranges[cdim].merge( range ); 870  } 871  range.clear(); 872  rval = writeUtil->gather_nodes_from_elements( ranges[dim], 0, range ); 873  CHK_MB_ERR_0( rval ); 874  ranges[0].merge( range ); 875  } 876  877  return initialize_mesh( ranges ); 878 } 879  880 // Gather all the mesh and related information to be written. 881 ErrorCode WriteHDF5::gather_all_mesh() 882 { 883  ErrorCode rval; 884  Range ranges[5]; 885  886  rval = iFace->get_entities_by_type( 0, MBVERTEX, ranges[0] ); 887  if( MB_SUCCESS != rval ) return error( rval ); 888  889  rval = iFace->get_entities_by_dimension( 0, 1, ranges[1] ); 890  if( MB_SUCCESS != rval ) return error( rval ); 891  892  rval = iFace->get_entities_by_dimension( 0, 2, ranges[2] ); 893  if( MB_SUCCESS != rval ) return error( rval ); 894  895  rval = iFace->get_entities_by_dimension( 0, 3, ranges[3] ); 896  if( MB_SUCCESS != rval ) return error( rval ); 897  898  rval = iFace->get_entities_by_type( 0, MBENTITYSET, ranges[4] ); 899  if( MB_SUCCESS != rval ) return error( rval ); 900  901  return initialize_mesh( ranges ); 902 } 903  904 ErrorCode WriteHDF5::write_nodes() 905 { 906  mhdf_Status status; 907  int dim, mesh_dim; 908  ErrorCode rval; 909  hid_t node_table; 910  long first_id, num_nodes; 911  912  if( !nodeSet.total_num_ents ) return MB_SUCCESS; // No nodes! 913  914  CHECK_OPEN_HANDLES; 915  916  rval = iFace->get_dimension( mesh_dim ); 917  CHK_MB_ERR_0( rval ); 918  919  debug_barrier(); 920  dbgOut.print( 3, "Opening Node Coords\n" ); 921  node_table = mhdf_openNodeCoords( filePtr, &num_nodes, &dim, &first_id, &status ); 922  CHK_MHDF_ERR_0( status ); 923  IODebugTrack track( debugTrack, "nodes", num_nodes ); 924  925  double* buffer = (double*)dataBuffer; 926 #ifdef BLOCKED_COORD_IO 927  int chunk_size = bufferSize / sizeof( double ); 928 #else 929  int chunk_size = bufferSize / ( 3 * sizeof( double ) ); 930 #endif 931  932  long remaining = nodeSet.range.size(); 933  long num_writes = ( remaining + chunk_size - 1 ) / chunk_size; 934  if( nodeSet.max_num_ents ) 935  { 936  assert( nodeSet.max_num_ents >= remaining ); 937  num_writes = ( nodeSet.max_num_ents + chunk_size - 1 ) / chunk_size; 938  } 939  long remaining_writes = num_writes; 940  941  long offset = nodeSet.offset; 942  Range::const_iterator iter = nodeSet.range.begin(); 943  dbgOut.printf( 3, "Writing %ld nodes in %ld blocks of %d\n", remaining, ( remaining + chunk_size - 1 ) / chunk_size, 944  chunk_size ); 945  while( remaining ) 946  { 947  (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 948  long count = chunk_size < remaining ? chunk_size : remaining; 949  remaining -= count; 950  Range::const_iterator end = iter; 951  end += count; 952  953 #ifdef BLOCKED_COORD_IO 954  for( int d = 0; d < dim; d++ ) 955  { 956  if( d < mesh_dim ) 957  { 958  rval = writeUtil->get_node_coords( d, iter, end, count, buffer ); 959  CHK_MB_ERR_1( rval, node_table, status ); 960  } 961  else 962  memset( buffer, 0, count * sizeof( double ) ); 963  964  dbgOut.printf( 3, " writing %c node chunk %ld of %ld, %ld values at %ld\n", (char)( 'X' + d ), 965  num_writes - remaining_writes + 1, num_writes, count, offset ); 966  mhdf_writeNodeCoordWithOpt( node_table, offset, count, d, buffer, writeProp, &status ); 967  CHK_MHDF_ERR_1( status, node_table ); 968  } 969 #else 970  rval = writeUtil->get_node_coords( -1, iter, end, 3 * count, buffer ); 971  CHK_MB_ERR_1( rval, node_table, status ); 972  dbgOut.printf( 3, " writing node chunk %ld of %ld, %ld values at %ld\n", num_writes - remaining_writes + 1, 973  num_writes, count, offset ); 974  mhdf_writeNodeCoordsWithOpt( node_table, offset, count, buffer, writeProp, &status ); 975  CHK_MHDF_ERR_1( status, node_table ); 976 #endif 977  track.record_io( offset, count ); 978  979  iter = end; 980  offset += count; 981  --remaining_writes; 982  } 983  984  // Do empty writes if necessary for parallel collective IO 985  if( collectiveIO ) 986  { 987  while( remaining_writes-- ) 988  { 989  assert( writeProp != H5P_DEFAULT ); 990 #ifdef BLOCKED_COORD_IO 991  for( int d = 0; d < dim; ++d ) 992  { 993  dbgOut.printf( 3, " writing (empty) %c node chunk %ld of %ld.\n", (char)( 'X' + d ), 994  num_writes - remaining_writes, num_writes ); 995  mhdf_writeNodeCoordWithOpt( node_table, offset, 0, d, 0, writeProp, &status ); 996  CHK_MHDF_ERR_1( status, node_table ); 997  } 998 #else 999  dbgOut.printf( 3, " writing (empty) node chunk %ld of %ld.\n", num_writes - remaining_writes, num_writes ); 1000  mhdf_writeNodeCoordsWithOpt( node_table, offset, 0, 0, writeProp, &status ); 1001  CHK_MHDF_ERR_1( status, node_table ); 1002 #endif 1003  } 1004  } 1005  1006  mhdf_closeData( filePtr, node_table, &status ); 1007  CHK_MHDF_ERR_0( status ); 1008  1009  track.all_reduce(); 1010  return MB_SUCCESS; 1011 } 1012  1013 ErrorCode WriteHDF5::write_elems( ExportSet& elems ) 1014 { 1015  mhdf_Status status; 1016  ErrorCode rval; 1017  long first_id; 1018  int nodes_per_elem; 1019  long table_size; 1020  1021  CHECK_OPEN_HANDLES; 1022  1023  debug_barrier(); 1024  dbgOut.printf( 2, "Writing %lu elements of type %s%d\n", (unsigned long)elems.range.size(), 1025  CN::EntityTypeName( elems.type ), elems.num_nodes ); 1026  dbgOut.print( 3, "Writing elements", elems.range ); 1027  1028  hid_t elem_table = mhdf_openConnectivity( filePtr, elems.name(), &nodes_per_elem, &table_size, &first_id, &status ); 1029  CHK_MHDF_ERR_0( status ); 1030  IODebugTrack track( debugTrack, elems.name() && strlen( elems.name() ) ? elems.name() : "<ANONYMOUS ELEM SET?>", 1031  table_size ); 1032  1033  assert( (unsigned long)first_id <= elems.first_id ); 1034  assert( (unsigned long)table_size >= elems.offset + elems.range.size() ); 1035  1036  EntityHandle* buffer = (EntityHandle*)dataBuffer; 1037  int chunk_size = bufferSize / ( elems.num_nodes * sizeof( wid_t ) ); 1038  long offset = elems.offset; 1039  long remaining = elems.range.size(); 1040  long num_writes = ( remaining + chunk_size - 1 ) / chunk_size; 1041  if( elems.max_num_ents ) 1042  { 1043  assert( elems.max_num_ents >= remaining ); 1044  num_writes = ( elems.max_num_ents + chunk_size - 1 ) / chunk_size; 1045  } 1046  long remaining_writes = num_writes; 1047  Range::iterator iter = elems.range.begin(); 1048  1049  while( remaining ) 1050  { 1051  (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 1052  long count = chunk_size < remaining ? chunk_size : remaining; 1053  remaining -= count; 1054  1055  Range::iterator next = iter; 1056  next += count; 1057  rval = writeUtil->get_element_connect( iter, next, elems.num_nodes, count * elems.num_nodes, buffer ); 1058  CHK_MB_ERR_1( rval, elem_table, status ); 1059  iter = next; 1060  1061  for( long i = 0; i < count * nodes_per_elem; ++i ) 1062  { 1063  buffer[i] = idMap.find( buffer[i] ); 1064  if( 0 == buffer[i] ) 1065  { 1066  MB_SET_ERR_CONT( "Invalid " << elems.name() << " element connectivity. Write Aborted" ); 1067  mhdf_closeData( filePtr, elem_table, &status ); 1068  return error( MB_FAILURE ); 1069  } 1070  } 1071  1072  dbgOut.printf( 3, " writing node connectivity %ld of %ld, %ld values at %ld\n", 1073  num_writes - remaining_writes + 1, num_writes, count, offset ); 1074  track.record_io( offset, count ); 1075  mhdf_writeConnectivityWithOpt( elem_table, offset, count, id_type, buffer, writeProp, &status ); 1076  CHK_MHDF_ERR_1( status, elem_table ); 1077  1078  offset += count; 1079  --remaining_writes; 1080  } 1081  1082  // Do empty writes if necessary for parallel collective IO 1083  if( collectiveIO ) 1084  { 1085  while( remaining_writes-- ) 1086  { 1087  assert( writeProp != H5P_DEFAULT ); 1088  dbgOut.printf( 3, " writing (empty) connectivity chunk %ld of %ld.\n", num_writes - remaining_writes + 1, 1089  num_writes ); 1090  mhdf_writeConnectivityWithOpt( elem_table, offset, 0, id_type, 0, writeProp, &status ); 1091  CHK_MHDF_ERR_1( status, elem_table ); 1092  } 1093  } 1094  1095  mhdf_closeData( filePtr, elem_table, &status ); 1096  CHK_MHDF_ERR_0( status ); 1097  1098  track.all_reduce(); 1099  return MB_SUCCESS; 1100 } 1101  1102 ErrorCode WriteHDF5::get_set_info( EntityHandle set, 1103  long& num_entities, 1104  long& num_children, 1105  long& num_parents, 1106  unsigned long& flags ) 1107 { 1108  ErrorCode rval; 1109  int i; 1110  unsigned int u; 1111  1112  rval = iFace->get_number_entities_by_handle( set, i, false ); 1113  CHK_MB_ERR_0( rval ); 1114  num_entities = i; 1115  1116  rval = iFace->num_child_meshsets( set, &i ); 1117  CHK_MB_ERR_0( rval ); 1118  num_children = i; 1119  1120  rval = iFace->num_parent_meshsets( set, &i ); 1121  CHK_MB_ERR_0( rval ); 1122  num_parents = i; 1123  1124  rval = iFace->get_meshset_options( set, u ); 1125  CHK_MB_ERR_0( rval ); 1126  flags = u; 1127  1128  return MB_SUCCESS; 1129 } 1130  1131 ErrorCode WriteHDF5::write_set_data( const WriteUtilIface::EntityListType which_data, 1132  const hid_t handle, 1133  IODebugTrack& track, 1134  Range* ranged, 1135  Range* null_stripped, 1136  std::vector< long >* set_sizes ) 1137 { 1138  // ranged must be non-null for CONTENTS and null for anything else 1139  assert( ( which_data == WriteUtilIface::CONTENTS ) == ( 0 != ranged ) ); 1140  ErrorCode rval; 1141  mhdf_Status status; 1142  1143  debug_barrier(); 1144  1145  // Function pointer type used to write set data 1146  void ( *write_func )( hid_t, long, long, hid_t, const void*, hid_t, mhdf_Status* ); 1147  long max_vals; // Max over all procs of number of values to write to data set 1148  long offset; // Offset in HDF5 dataset at which to write next block of data 1149  switch( which_data ) 1150  { 1151  case WriteUtilIface::CONTENTS: 1152  assert( ranged != 0 && null_stripped != 0 && set_sizes != 0 ); 1153  write_func = &mhdf_writeSetDataWithOpt; 1154  max_vals = maxNumSetContents; 1155  offset = setContentsOffset; 1156  dbgOut.print( 2, "Writing set contents\n" ); 1157  break; 1158  case WriteUtilIface::CHILDREN: 1159  assert( !ranged && !null_stripped && !set_sizes ); 1160  write_func = &mhdf_writeSetParentsChildrenWithOpt; 1161  max_vals = maxNumSetChildren; 1162  offset = setChildrenOffset; 1163  dbgOut.print( 2, "Writing set child lists\n" ); 1164  break; 1165  case WriteUtilIface::PARENTS: 1166  assert( !ranged && !null_stripped && !set_sizes ); 1167  write_func = &mhdf_writeSetParentsChildrenWithOpt; 1168  max_vals = maxNumSetParents; 1169  offset = setParentsOffset; 1170  dbgOut.print( 2, "Writing set parent lists\n" ); 1171  break; 1172  default: 1173  assert( false ); 1174  return MB_FAILURE; 1175  } 1176  // assert(max_vals > 0); // Should have skipped this function otherwise 1177  1178  // buffer to use for IO 1179  wid_t* buffer = reinterpret_cast< wid_t* >( dataBuffer ); 1180  // number of handles that will fit in the buffer 1181  const size_t buffer_size = bufferSize / sizeof( EntityHandle ); 1182  // the total number of write calls that must be made, including no-ops for collective io 1183  const size_t num_total_writes = ( max_vals + buffer_size - 1 ) / buffer_size; 1184  1185  std::vector< SpecialSetData >::iterator si = specialSets.begin(); 1186  1187  std::vector< wid_t > remaining; // data left over from prev iteration because it didn't fit in buffer 1188  size_t remaining_offset = 0; // avoid erasing from front of 'remaining' 1189  const EntityHandle* remaining_ptr = 0; // remaining for non-ranged data 1190  size_t remaining_count = 0; 1191  const wid_t* special_rem_ptr = 0; 1192  Range::const_iterator i = setSet.range.begin(), j, rhint, nshint; 1193  if( ranged ) rhint = ranged->begin(); 1194  if( null_stripped ) nshint = null_stripped->begin(); 1195  for( size_t w = 0; w < num_total_writes; ++w ) 1196  { 1197  if( i == setSet.range.end() && !remaining.empty() && !remaining_ptr ) 1198  { 1199  // If here, then we've written everything but we need to 1200  // make more write calls because we're doing collective IO 1201  // in parallel 1202  ( *write_func )( handle, 0, 0, id_type, 0, writeProp, &status ); 1203  CHK_MHDF_ERR_0( status ); 1204  continue; 1205  } 1206  1207  // If we had some left-over data from a range-compacted set 1208  // from the last iteration, add it to the buffer now 1209  size_t count = 0; 1210  if( !remaining.empty() ) 1211  { 1212  count = remaining.size() - remaining_offset; 1213  if( count > buffer_size ) 1214  { 1215  memcpy( buffer, &remaining[remaining_offset], buffer_size * sizeof( wid_t ) ); 1216  count = buffer_size; 1217  remaining_offset += buffer_size; 1218  } 1219  else 1220  { 1221  memcpy( buffer, &remaining[remaining_offset], count * sizeof( wid_t ) ); 1222  remaining_offset = 0; 1223  remaining.clear(); 1224  } 1225  } 1226  // If we had some left-over data from a non-range-compacted set 1227  // from the last iteration, add it to the buffer now 1228  else if( remaining_ptr ) 1229  { 1230  if( remaining_count > buffer_size ) 1231  { 1232  rval = vector_to_id_list( remaining_ptr, buffer, buffer_size ); 1233  CHK_MB_ERR_0( rval ); 1234  count = buffer_size; 1235  remaining_ptr += count; 1236  remaining_count -= count; 1237  } 1238  else 1239  { 1240  rval = vector_to_id_list( remaining_ptr, buffer, remaining_count ); 1241  CHK_MB_ERR_0( rval ); 1242  count = remaining_count; 1243  remaining_ptr = 0; 1244  remaining_count = 0; 1245  } 1246  } 1247  // If we had some left-over data from a "special" (i.e. parallel shared) 1248  // set. 1249  else if( special_rem_ptr ) 1250  { 1251  if( remaining_count > buffer_size ) 1252  { 1253  memcpy( buffer, special_rem_ptr, buffer_size * sizeof( wid_t ) ); 1254  count = buffer_size; 1255  special_rem_ptr += count; 1256  remaining_count -= count; 1257  } 1258  else 1259  { 1260  memcpy( buffer, special_rem_ptr, remaining_count * sizeof( wid_t ) ); 1261  count = remaining_count; 1262  special_rem_ptr = 0; 1263  remaining_count = 0; 1264  } 1265  } 1266  1267  // While there is both space remaining in the buffer and 1268  // more sets to write, append more set data to buffer. 1269  1270  while( count < buffer_size && i != setSet.range.end() ) 1271  { 1272  // Special case for "special" (i.e. parallel shared) sets: 1273  // we already have the data in a vector, just copy it. 1274  if( si != specialSets.end() && si->setHandle == *i ) 1275  { 1276  std::vector< wid_t >& list = ( which_data == WriteUtilIface::CONTENTS ) ? si->contentIds 1277  : ( which_data == WriteUtilIface::PARENTS ) ? si->parentIds 1278  : si->childIds; 1279  size_t append = list.size(); 1280  if( count + list.size() > buffer_size ) 1281  { 1282  append = buffer_size - count; 1283  special_rem_ptr = &list[append]; 1284  remaining_count = list.size() - append; 1285  } 1286  memcpy( buffer + count, &list[0], append * sizeof( wid_t ) ); 1287  ++i; 1288  ++si; 1289  count += append; 1290  continue; 1291  } 1292  1293  j = i; 1294  ++i; 1295  const EntityHandle* ptr; 1296  int len; 1297  unsigned char flags; 1298  rval = writeUtil->get_entity_list_pointers( j, i, &ptr, which_data, &len, &flags ); 1299  if( MB_SUCCESS != rval ) return rval; 1300  if( which_data == WriteUtilIface::CONTENTS && !( flags & MESHSET_ORDERED ) ) 1301  { 1302  bool compacted; 1303  remaining.clear(); 1304  if( len == 0 ) 1305  compacted = false; 1306  else 1307  { 1308  assert( !( len % 2 ) ); 1309  rval = range_to_blocked_list( ptr, len / 2, remaining, compacted ); 1310  if( MB_SUCCESS != rval ) return rval; 1311  } 1312  if( compacted ) 1313  { 1314  rhint = ranged->insert( rhint, *j ); 1315  set_sizes->push_back( remaining.size() ); 1316  } 1317  else if( remaining.size() != (unsigned)len ) 1318  { 1319  nshint = null_stripped->insert( nshint, *j ); 1320  set_sizes->push_back( remaining.size() ); 1321  } 1322  1323  if( count + remaining.size() <= buffer_size ) 1324  { 1325  if( !remaining.empty() ) 1326  memcpy( buffer + count, &remaining[0], sizeof( wid_t ) * remaining.size() ); 1327  count += remaining.size(); 1328  remaining.clear(); 1329  remaining_offset = 0; 1330  } 1331  else 1332  { 1333  remaining_offset = buffer_size - count; 1334  memcpy( buffer + count, &remaining[0], sizeof( wid_t ) * remaining_offset ); 1335  count += remaining_offset; 1336  } 1337  } 1338  else 1339  { 1340  if( count + len > buffer_size ) 1341  { 1342  size_t append = buffer_size - count; 1343  remaining_ptr = ptr + append; 1344  remaining_count = len - append; 1345  len = append; 1346  } 1347  1348  rval = vector_to_id_list( ptr, buffer + count, len ); 1349  count += len; 1350  } 1351  } 1352  1353  // Write the buffer. 1354  ( *write_func )( handle, offset, count, id_type, buffer, writeProp, &status ); 1355  CHK_MHDF_ERR_0( status ); 1356  track.record_io( offset, count ); 1357  offset += count; 1358  } 1359  1360  return MB_SUCCESS; 1361 } 1362  1363 ErrorCode WriteHDF5::write_sets( double* times ) 1364 { 1365  mhdf_Status status; 1366  ErrorCode rval; 1367  long first_id, size; 1368  hid_t table; 1369  CpuTimer timer; 1370  1371  CHECK_OPEN_HANDLES; 1372  /* If no sets, just return success */ 1373  if( !writeSets ) return MB_SUCCESS; 1374  1375  debug_barrier(); 1376  dbgOut.printf( 2, "Writing %lu non-shared sets\n", (unsigned long)setSet.range.size() ); 1377  dbgOut.print( 3, "Non-shared sets", setSet.range ); 1378  1379  /* Write set parents */ 1380  if( writeSetParents ) 1381  { 1382  topState.start( "writing parent lists for local sets" ); 1383  table = mhdf_openSetParents( filePtr, &size, &status ); 1384  CHK_MHDF_ERR_0( status ); 1385  IODebugTrack track( debugTrack, "SetParents", size ); 1386  1387  rval = write_set_data( WriteUtilIface::PARENTS, table, track ); 1388  topState.end( rval ); 1389  CHK_MB_ERR_1( rval, table, status ); 1390  1391  mhdf_closeData( filePtr, table, &status ); 1392  CHK_MHDF_ERR_0( status ); 1393  1394  times[SET_PARENT] = timer.time_elapsed(); 1395  track.all_reduce(); 1396  } 1397  1398  /* Write set children */ 1399  if( writeSetChildren ) 1400  { 1401  topState.start( "writing child lists for local sets" ); 1402  table = mhdf_openSetChildren( filePtr, &size, &status ); 1403  CHK_MHDF_ERR_0( status ); 1404  IODebugTrack track( debugTrack, "SetChildren", size ); 1405  1406  rval = write_set_data( WriteUtilIface::CHILDREN, table, track ); 1407  topState.end( rval ); 1408  CHK_MB_ERR_1( rval, table, status ); 1409  1410  mhdf_closeData( filePtr, table, &status ); 1411  CHK_MHDF_ERR_0( status ); 1412  1413  times[SET_CHILD] = timer.time_elapsed(); 1414  track.all_reduce(); 1415  } 1416  1417  /* Write set contents */ 1418  Range ranged_sets, null_stripped_sets; 1419  std::vector< long > set_sizes; 1420  if( writeSetContents ) 1421  { 1422  topState.start( "writing content lists for local sets" ); 1423  table = mhdf_openSetData( filePtr, &size, &status ); 1424  CHK_MHDF_ERR_0( status ); 1425  IODebugTrack track( debugTrack, "SetContents", size ); 1426  1427  rval = write_set_data( WriteUtilIface::CONTENTS, table, track, &ranged_sets, &null_stripped_sets, &set_sizes ); 1428  topState.end( rval ); 1429  CHK_MB_ERR_1( rval, table, status ); 1430  1431  mhdf_closeData( filePtr, table, &status ); 1432  CHK_MHDF_ERR_0( status ); 1433  1434  times[SET_CONTENT] = timer.time_elapsed(); 1435  track.all_reduce(); 1436  } 1437  assert( ranged_sets.size() + null_stripped_sets.size() == set_sizes.size() ); 1438  1439  /* Write set description table */ 1440  1441  debug_barrier(); 1442  topState.start( "writing descriptions of local sets" ); 1443  dbgOut.printf( 2, "Writing %lu non-shared sets\n", (unsigned long)setSet.range.size() ); 1444  dbgOut.print( 3, "Non-shared sets", setSet.range ); 1445  1446  /* Open the table */ 1447  table = mhdf_openSetMeta( filePtr, &size, &first_id, &status ); 1448  CHK_MHDF_ERR_0( status ); 1449  IODebugTrack track_meta( debugTrack, "SetMeta", size ); 1450  1451  /* Some debug stuff */ 1452  debug_barrier(); 1453  dbgOut.printf( 2, "Writing %lu non-shared sets\n", (unsigned long)setSet.range.size() ); 1454  dbgOut.print( 3, "Non-shared sets", setSet.range ); 1455  1456  /* Counts and buffers and such */ 1457  mhdf_index_t* const buffer = reinterpret_cast< mhdf_index_t* >( dataBuffer ); 1458  const size_t buffer_size = bufferSize / ( 4 * sizeof( mhdf_index_t ) ); 1459  const size_t num_local_writes = ( setSet.range.size() + buffer_size - 1 ) / buffer_size; 1460  const size_t num_global_writes = ( setSet.max_num_ents + buffer_size - 1 ) / buffer_size; 1461  assert( num_local_writes <= num_global_writes ); 1462  assert( num_global_writes > 0 ); 1463  1464  /* data about sets for which number of handles written is 1465  * not the same as the number of handles in the set 1466  * (range-compacted or null handles stripped out) 1467  */ 1468  Range::const_iterator i = setSet.range.begin(); 1469  Range::const_iterator r = ranged_sets.begin(); 1470  Range::const_iterator s = null_stripped_sets.begin(); 1471  std::vector< mhdf_index_t >::const_iterator n = set_sizes.begin(); 1472  assert( ranged_sets.size() + null_stripped_sets.size() == set_sizes.size() ); 1473  1474  /* We write the end index for each list, rather than the count */ 1475  mhdf_index_t prev_contents_end = setContentsOffset - 1; 1476  mhdf_index_t prev_children_end = setChildrenOffset - 1; 1477  mhdf_index_t prev_parents_end = setParentsOffset - 1; 1478  1479  /* While there is more data to write */ 1480  size_t offset = setSet.offset; 1481  std::vector< SpecialSetData >::const_iterator si = specialSets.begin(); 1482  for( size_t w = 0; w < num_local_writes; ++w ) 1483  { 1484  // Get a buffer full of data 1485  size_t count = 0; 1486  while( count < buffer_size && i != setSet.range.end() ) 1487  { 1488  // Get set properties 1489  long num_ent, num_child, num_parent; 1490  unsigned long flags; 1491  if( si != specialSets.end() && si->setHandle == *i ) 1492  { 1493  flags = si->setFlags; 1494  num_ent = si->contentIds.size(); 1495  num_child = si->childIds.size(); 1496  num_parent = si->parentIds.size(); 1497  ++si; 1498  if( r != ranged_sets.end() && *i == *r ) 1499  { 1500  assert( flags & mhdf_SET_RANGE_BIT ); 1501  ++r; 1502  ++n; 1503  } 1504  else if( s != null_stripped_sets.end() && *i == *s ) 1505  { 1506  ++s; 1507  ++n; 1508  } 1509  } 1510  else 1511  { 1512  assert( si == specialSets.end() || si->setHandle > *i ); 1513  1514  // Get set properties 1515  rval = get_set_info( *i, num_ent, num_child, num_parent, flags ); 1516  CHK_MB_ERR_1( rval, table, status ); 1517  1518  // Check if size is something other than num handles in set 1519  if( r != ranged_sets.end() && *i == *r ) 1520  { 1521  num_ent = *n; 1522  ++r; 1523  ++n; 1524  flags |= mhdf_SET_RANGE_BIT; 1525  } 1526  else if( s != null_stripped_sets.end() && *i == *s ) 1527  { 1528  num_ent = *n; 1529  ++s; 1530  ++n; 1531  } 1532  } 1533  1534  // Put data in buffer 1535  mhdf_index_t* local = buffer + 4 * count; 1536  prev_contents_end += num_ent; 1537  prev_children_end += num_child; 1538  prev_parents_end += num_parent; 1539  local[0] = prev_contents_end; 1540  local[1] = prev_children_end; 1541  local[2] = prev_parents_end; 1542  local[3] = flags; 1543  1544  // Iterate 1545  ++count; 1546  ++i; 1547  } 1548  1549  // Write the data 1550  mhdf_writeSetMetaWithOpt( table, offset, count, MHDF_INDEX_TYPE, buffer, writeProp, &status ); 1551  CHK_MHDF_ERR_1( status, table ); 1552  track_meta.record_io( offset, count ); 1553  offset += count; 1554  } 1555  assert( r == ranged_sets.end() ); 1556  assert( s == null_stripped_sets.end() ); 1557  assert( n == set_sizes.end() ); 1558  1559  /* If doing parallel write with collective IO, do null write 1560  * calls because other procs aren't done yet and write calls 1561  * are collective */ 1562  for( size_t w = num_local_writes; w != num_global_writes; ++w ) 1563  { 1564  mhdf_writeSetMetaWithOpt( table, 0, 0, MHDF_INDEX_TYPE, 0, writeProp, &status ); 1565  CHK_MHDF_ERR_1( status, table ); 1566  } 1567  1568  topState.end(); 1569  mhdf_closeData( filePtr, table, &status ); 1570  CHK_MHDF_ERR_0( status ); 1571  1572  times[SET_META] = timer.time_elapsed(); 1573  track_meta.all_reduce(); 1574  1575  return MB_SUCCESS; 1576 } 1577  1578 template < class HandleRangeIter > 1579 inline size_t count_num_handles( HandleRangeIter iter, HandleRangeIter end ) 1580 { 1581  size_t result = 0; 1582  for( ; iter != end; ++iter ) 1583  result += iter->second - iter->first + 1; 1584  1585  return result; 1586 } 1587  1588 template < class HandleRangeIter > 1589 inline ErrorCode range_to_id_list_templ( HandleRangeIter begin, 1590  HandleRangeIter end, 1591  const RangeMap< EntityHandle, WriteHDF5::wid_t >& idMap, 1592  WriteHDF5::wid_t* array ) 1593 { 1594  ErrorCode rval = MB_SUCCESS; 1595  RangeMap< EntityHandle, WriteHDF5::wid_t >::iterator ri = idMap.begin(); 1596  WriteHDF5::wid_t* i = array; 1597  for( HandleRangeIter pi = begin; pi != end; ++pi ) 1598  { 1599  EntityHandle h = pi->first; 1600  while( h <= pi->second ) 1601  { 1602  ri = idMap.lower_bound( ri, idMap.end(), h ); 1603  if( ri == idMap.end() || ri->begin > h ) 1604  { 1605  rval = MB_ENTITY_NOT_FOUND; 1606  *i = 0; 1607  ++i; 1608  ++h; 1609  continue; 1610  } 1611  1612  // compute the last available value of the found target range (ri iterator) 1613  WriteHDF5::wid_t last_valid_input_value_in_current_map_range = ri->begin + ri->count - 1; 1614  // limit the number of steps we do on top of h so we do not overflow the output range 1615  // span 1616  WriteHDF5::wid_t step_until = std::min( last_valid_input_value_in_current_map_range, pi->second ); 1617  WriteHDF5::wid_t n = step_until - h + 1; 1618  assert( n > 0 ); // We must at least step 1 1619  1620  WriteHDF5::wid_t id = ri->value + ( h - ri->begin ); 1621  for( WriteHDF5::wid_t j = 0; j < n; ++i, ++j ) 1622  *i = id + j; 1623  h += n; 1624  } 1625  } 1626  1627  assert( i == array + count_num_handles( begin, end ) ); 1628  return rval; 1629 } 1630  1631 template < class HandleRangeIter > 1632 inline ErrorCode range_to_blocked_list_templ( HandleRangeIter begin, 1633  HandleRangeIter end, 1634  const RangeMap< EntityHandle, WriteHDF5::wid_t >& idMap, 1635  std::vector< WriteHDF5::wid_t >& output_id_list, 1636  bool& ranged_list ) 1637 { 1638  output_id_list.clear(); 1639  if( begin == end ) 1640  { 1641  ranged_list = false; 1642  return MB_SUCCESS; 1643  } 1644  1645  // First try ranged format, but give up if we reach the 1646  // non-range format size. 1647  RangeMap< EntityHandle, WriteHDF5::wid_t >::iterator ri = idMap.begin(); 1648  1649  const size_t num_handles = count_num_handles( begin, end ); 1650  // If we end up with more than this many range blocks, then 1651  // we're better off just writing the set as a simple list 1652  size_t pairs_remaining = num_handles / 2; 1653  for( HandleRangeIter pi = begin; pi != end; ++pi ) 1654  { 1655  EntityHandle h = pi->first; 1656  WriteHDF5::wid_t local_mapped_from_subrange = 0; 1657  while( h <= pi->second ) 1658  { 1659  ri = idMap.lower_bound( ri, idMap.end(), h ); 1660  if( ri == idMap.end() || ri->begin > h ) 1661  { 1662  ++h; 1663  continue; 1664  } 1665  1666  WriteHDF5::wid_t n = pi->second - pi->first + 1 - local_mapped_from_subrange; 1667  if( n > ri->count ) n = ri->count; 1668  1669  WriteHDF5::wid_t id = ri->value + ( h - ri->begin ); 1670  // see if we can go to the end of the range 1671  if( id + n > ri->value + ri->count ) // we have to reduce n, because we cannot go over next subrange 1672  { 1673  if( ri->value + ri->count - id > 0 ) n = ri->value + ri->count - id; 1674  } 1675  1676  // See if we can append it to the previous range 1677  if( !output_id_list.empty() && output_id_list[output_id_list.size() - 2] + output_id_list.back() == id ) 1678  { 1679  output_id_list.back() += n; 1680  } 1681  1682  // If we ran out of space, (or set is empty) just do list format 1683  else if( !pairs_remaining ) 1684  { 1685  ranged_list = false; 1686  output_id_list.resize( num_handles ); 1687  range_to_id_list_templ( begin, end, idMap, &output_id_list[0] ); 1688  output_id_list.erase( std::remove( output_id_list.begin(), output_id_list.end(), 0u ), 1689  output_id_list.end() ); 1690  return MB_SUCCESS; 1691  } 1692  1693  // 1694  else 1695  { 1696  --pairs_remaining; 1697  output_id_list.push_back( id ); 1698  output_id_list.push_back( n ); 1699  } 1700  local_mapped_from_subrange += n; // we already mapped so many 1701  h += n; 1702  } 1703  } 1704  1705  ranged_list = true; 1706  return MB_SUCCESS; 1707 } 1708  1709 ErrorCode WriteHDF5::range_to_blocked_list( const Range& input_range, 1710  std::vector< wid_t >& output_id_list, 1711  bool& ranged_list ) 1712 { 1713  return range_to_blocked_list_templ( input_range.const_pair_begin(), input_range.const_pair_end(), idMap, 1714  output_id_list, ranged_list ); 1715 } 1716  1717 ErrorCode WriteHDF5::range_to_blocked_list( const EntityHandle* array, 1718  size_t num_input_ranges, 1719  std::vector< wid_t >& output_id_list, 1720  bool& ranged_list ) 1721 { 1722  // We assume this in the cast on the following line 1723  typedef std::pair< EntityHandle, EntityHandle > mtype; 1724  assert( sizeof( mtype ) == 2 * sizeof( EntityHandle ) ); 1725  const mtype* arr = reinterpret_cast< const mtype* >( array ); 1726  return range_to_blocked_list_templ( arr, arr + num_input_ranges, idMap, output_id_list, ranged_list ); 1727 } 1728  1729 ErrorCode WriteHDF5::range_to_id_list( const Range& range, wid_t* array ) 1730 { 1731  return range_to_id_list_templ( range.const_pair_begin(), range.const_pair_end(), idMap, array ); 1732 } 1733  1734 ErrorCode WriteHDF5::vector_to_id_list( const EntityHandle* input, 1735  size_t input_len, 1736  wid_t* output, 1737  size_t& output_len, 1738  bool remove_zeros ) 1739 { 1740  const EntityHandle* i_iter = input; 1741  const EntityHandle* i_end = input + input_len; 1742  wid_t* o_iter = output; 1743  for( ; i_iter != i_end; ++i_iter ) 1744  { 1745  wid_t id = idMap.find( *i_iter ); 1746  if( !remove_zeros || id != 0 ) 1747  { 1748  *o_iter = id; 1749  ++o_iter; 1750  } 1751  } 1752  output_len = o_iter - output; 1753  1754  return MB_SUCCESS; 1755 } 1756  1757 ErrorCode WriteHDF5::vector_to_id_list( const std::vector< EntityHandle >& input, 1758  std::vector< wid_t >& output, 1759  bool remove_zeros ) 1760 { 1761  output.resize( input.size() ); 1762  size_t output_size = 0; 1763  ErrorCode rval = vector_to_id_list( &input[0], input.size(), &output[0], output_size, remove_zeros ); 1764  output.resize( output_size ); 1765  return rval; 1766 } 1767  1768 ErrorCode WriteHDF5::vector_to_id_list( const EntityHandle* input, wid_t* output, size_t count ) 1769 { 1770  size_t output_len; 1771  return vector_to_id_list( input, count, output, output_len, false ); 1772 } 1773  1774 inline ErrorCode WriteHDF5::get_adjacencies( EntityHandle entity, std::vector< wid_t >& adj ) 1775 { 1776  const EntityHandle* adj_array; 1777  int num_adj; 1778  ErrorCode rval = writeUtil->get_adjacencies( entity, adj_array, num_adj ); 1779  if( MB_SUCCESS != rval ) return error( rval ); 1780  1781  size_t j = 0; 1782  adj.resize( num_adj ); 1783  for( int i = 0; i < num_adj; ++i ) 1784  if( wid_t id = idMap.find( adj_array[i] ) ) adj[j++] = id; 1785  adj.resize( j ); 1786  1787  return MB_SUCCESS; 1788 } 1789  1790 ErrorCode WriteHDF5::write_adjacencies( const ExportSet& elements ) 1791 { 1792  ErrorCode rval; 1793  mhdf_Status status; 1794  Range::const_iterator iter; 1795  const Range::const_iterator end = elements.range.end(); 1796  std::vector< wid_t > adj_list; 1797  1798  CHECK_OPEN_HANDLES; 1799  1800  debug_barrier(); 1801  1802  /* Count Adjacencies */ 1803  long count = 0; 1804  // for (iter = elements.range.begin(); iter != end; ++iter) { 1805  // adj_list.clear(); 1806  // rval = get_adjacencies(*iter, adj_list);CHK_MB_ERR_0(rval); 1807  // 1808  // if (adj_list.size() > 0) 1809  // count += adj_list.size() + 2; 1810  //} 1811  1812  // if (count == 0) 1813  // return MB_SUCCESS; 1814  1815  long offset = elements.adj_offset; 1816  if( elements.max_num_adjs == 0 ) return MB_SUCCESS; 1817  1818  /* Create data list */ 1819  hid_t table = mhdf_openAdjacency( filePtr, elements.name(), &count, &status ); 1820  CHK_MHDF_ERR_0( status ); 1821  IODebugTrack track( debugTrack, "Adjacencies", count ); 1822  1823  /* Write data */ 1824  wid_t* buffer = (wid_t*)dataBuffer; 1825  long chunk_size = bufferSize / sizeof( wid_t ); 1826  long num_writes = ( elements.max_num_adjs + chunk_size - 1 ) / chunk_size; 1827  (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 1828  count = 0; 1829  for( iter = elements.range.begin(); iter != end; ++iter ) 1830  { 1831  adj_list.clear(); 1832  rval = get_adjacencies( *iter, adj_list ); 1833  CHK_MB_ERR_1( rval, table, status ); 1834  if( adj_list.size() == 0 ) continue; 1835  1836  // If buffer is full, flush it 1837  if( count + adj_list.size() + 2 > (unsigned long)chunk_size ) 1838  { 1839  dbgOut.print( 3, " writing adjacency chunk.\n" ); 1840  track.record_io( offset, count ); 1841  mhdf_writeAdjacencyWithOpt( table, offset, count, id_type, buffer, writeProp, &status ); 1842  CHK_MHDF_ERR_1( status, table ); 1843  (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 1844  1845  offset += count; 1846  count = 0; 1847  } 1848  1849  buffer[count++] = idMap.find( *iter ); 1850  buffer[count++] = adj_list.size(); 1851  1852  assert( adj_list.size() + 2 < (unsigned long)chunk_size ); 1853  memcpy( buffer + count, &adj_list[0], adj_list.size() * sizeof( wid_t ) ); 1854  count += adj_list.size(); 1855  } 1856  1857  if( count ) 1858  { 1859  dbgOut.print( 2, " writing final adjacency chunk.\n" ); 1860  mhdf_writeAdjacencyWithOpt( table, offset, count, id_type, buffer, writeProp, &status ); 1861  CHK_MHDF_ERR_1( status, table ); 1862  1863  offset += count; 1864  count = 0; 1865  --num_writes; 1866  } 1867  1868  // Do empty writes if necessary for parallel collective IO 1869  if( collectiveIO ) 1870  { 1871  while( num_writes > 0 ) 1872  { 1873  --num_writes; 1874  assert( writeProp != H5P_DEFAULT ); 1875  dbgOut.print( 2, " writing empty adjacency chunk.\n" ); 1876  mhdf_writeAdjacencyWithOpt( table, offset, 0, id_type, 0, writeProp, &status ); 1877  CHK_MHDF_ERR_1( status, table ); 1878  } 1879  } 1880  1881  mhdf_closeData( filePtr, table, &status ); 1882  CHK_MHDF_ERR_0( status ); 1883  1884  track.all_reduce(); 1885  return MB_SUCCESS; 1886 } 1887  1888 ErrorCode WriteHDF5::write_tag( const TagDesc& tag_data, double* times ) 1889 { 1890  std::string name; 1891  ErrorCode rval = iFace->tag_get_name( tag_data.tag_id, name ); 1892  if( MB_SUCCESS != rval ) return error( rval ); 1893  1894  CHECK_OPEN_HANDLES; 1895  debug_barrier(); 1896  dbgOut.tprintf( 1, "Writing tag: \"%s\"\n", name.c_str() ); 1897  1898  int moab_size, elem_size, array_len; 1899  DataType moab_type; 1900  mhdf_TagDataType mhdf_type; 1901  hid_t hdf5_type; 1902  rval = get_tag_size( tag_data.tag_id, moab_type, moab_size, elem_size, array_len, mhdf_type, hdf5_type ); 1903  if( MB_SUCCESS != rval ) return error( rval ); 1904  1905  CpuTimer timer; 1906  if( array_len == MB_VARIABLE_LENGTH && tag_data.write_sparse ) 1907  { 1908  dbgOut.printf( 2, "Writing sparse data for var-len tag: \"%s\"\n", name.c_str() ); 1909  rval = write_var_len_tag( tag_data, name, moab_type, hdf5_type, elem_size ); 1910  times[VARLEN_TAG_TIME] += timer.time_elapsed(); 1911  } 1912  else 1913  { 1914  int data_len = elem_size; 1915  if( moab_type != MB_TYPE_BIT ) data_len *= array_len; 1916  if( tag_data.write_sparse ) 1917  { 1918  dbgOut.printf( 2, "Writing sparse data for tag: \"%s\"\n", name.c_str() ); 1919  rval = write_sparse_tag( tag_data, name, moab_type, hdf5_type, data_len ); 1920  times[SPARSE_TAG_TIME] += timer.time_elapsed(); 1921  } 1922  for( size_t i = 0; MB_SUCCESS == rval && i < tag_data.dense_list.size(); ++i ) 1923  { 1924  const ExportSet* set = find( tag_data.dense_list[i] ); 1925  assert( 0 != set ); 1926  debug_barrier(); 1927  dbgOut.printf( 2, "Writing dense data for tag: \"%s\" on group \"%s\"\n", name.c_str(), set->name() ); 1928  subState.start( "writing dense data for tag: ", ( name + ":" + set->name() ).c_str() ); 1929  rval = write_dense_tag( tag_data, *set, name, moab_type, hdf5_type, data_len ); 1930  subState.end( rval ); 1931  } 1932  times[DENSE_TAG_TIME] += timer.time_elapsed(); 1933  } 1934  1935  H5Tclose( hdf5_type ); 1936  return MB_SUCCESS == rval ? MB_SUCCESS : error( rval ); 1937 } 1938  1939 ErrorCode WriteHDF5::write_sparse_ids( const TagDesc& tag_data, 1940  const Range& range, 1941  hid_t id_table, 1942  size_t table_size, 1943  const char* name ) 1944 { 1945  ErrorCode rval; 1946  mhdf_Status status; 1947  1948  CHECK_OPEN_HANDLES; 1949  1950  std::string tname( name ? name : "<UNKNOWN TAG?>" ); 1951  tname += " - Ids"; 1952  IODebugTrack track( debugTrack, tname, table_size ); 1953  1954  // Set up data buffer for writing IDs 1955  size_t chunk_size = bufferSize / sizeof( wid_t ); 1956  wid_t* id_buffer = (wid_t*)dataBuffer; 1957  1958  // Write IDs of tagged entities. 1959  long remaining = range.size(); 1960  long offset = tag_data.sparse_offset; 1961  long num_writes = ( remaining + chunk_size - 1 ) / chunk_size; 1962  if( tag_data.max_num_ents ) 1963  { 1964  assert( tag_data.max_num_ents >= (unsigned long)remaining ); 1965  num_writes = ( tag_data.max_num_ents + chunk_size - 1 ) / chunk_size; 1966  } 1967  Range::const_iterator iter = range.begin(); 1968  while( remaining ) 1969  { 1970  (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 1971  1972  // Write "chunk_size" blocks of data 1973  long count = (unsigned long)remaining > chunk_size ? chunk_size : remaining; 1974  remaining -= count; 1975  Range::const_iterator stop = iter; 1976  stop += count; 1977  Range tmp; 1978  ; 1979  tmp.merge( iter, stop ); 1980  iter = stop; 1981  assert( tmp.size() == (unsigned)count ); 1982  1983  rval = range_to_id_list( tmp, id_buffer ); 1984  CHK_MB_ERR_0( rval ); 1985  1986  // Write the data 1987  dbgOut.print( 3, " writing sparse tag entity chunk.\n" ); 1988  track.record_io( offset, count ); 1989  mhdf_writeSparseTagEntitiesWithOpt( id_table, offset, count, id_type, id_buffer, writeProp, &status ); 1990  CHK_MHDF_ERR_0( status ); 1991  1992  offset += count; 1993  --num_writes; 1994  } // while (remaining) 1995  1996  // Do empty writes if necessary for parallel collective IO 1997  if( collectiveIO ) 1998  { 1999  while( num_writes-- ) 2000  { 2001  assert( writeProp != H5P_DEFAULT ); 2002  dbgOut.print( 3, " writing empty sparse tag entity chunk.\n" ); 2003  mhdf_writeSparseTagEntitiesWithOpt( id_table, offset, 0, id_type, 0, writeProp, &status ); 2004  CHK_MHDF_ERR_0( status ); 2005  } 2006  } 2007  2008  track.all_reduce(); 2009  return MB_SUCCESS; 2010 } 2011  2012 ErrorCode WriteHDF5::write_sparse_tag( const TagDesc& tag_data, 2013  const std::string& name, 2014  DataType mb_data_type, 2015  hid_t value_type, 2016  int value_type_size ) 2017 { 2018  ErrorCode rval; 2019  mhdf_Status status; 2020  hid_t tables[3]; 2021  long table_size, data_size; 2022  2023  CHECK_OPEN_HANDLES; 2024  2025  // Get entities for which to write tag values 2026  Range range; 2027  rval = get_sparse_tagged_entities( tag_data, range ); 2028  2029  // Open tables to write info 2030  mhdf_openSparseTagData( filePtr, name.c_str(), &table_size, &data_size, tables, &status ); 2031  CHK_MHDF_ERR_0( status ); 2032  assert( range.size() + tag_data.sparse_offset <= (unsigned long)table_size ); 2033  // Fixed-length tag 2034  assert( table_size == data_size ); 2035  2036  // Write IDs for tagged entities 2037  subState.start( "writing sparse ids for tag: ", name.c_str() ); 2038  rval = write_sparse_ids( tag_data, range, tables[0], table_size, name.c_str() ); 2039  subState.end( rval ); 2040  CHK_MB_ERR_2( rval, tables, status ); 2041  mhdf_closeData( filePtr, tables[0], &status ); 2042  CHK_MHDF_ERR_1( status, tables[1] ); 2043  2044  // Set up data buffer for writing tag values 2045  IODebugTrack track( debugTrack, name + " Data", data_size ); 2046  subState.start( "writing sparse values for tag: ", name.c_str() ); 2047  rval = write_tag_values( tag_data.tag_id, tables[1], tag_data.sparse_offset, range, mb_data_type, value_type, 2048  value_type_size, tag_data.max_num_ents, track ); 2049  subState.end( rval ); 2050  CHK_MB_ERR_0( rval ); 2051  mhdf_closeData( filePtr, tables[1], &status ); 2052  CHK_MHDF_ERR_0( status ); 2053  2054  track.all_reduce(); 2055  return MB_SUCCESS; 2056 } 2057  2058 ErrorCode WriteHDF5::write_var_len_indices( const TagDesc& tag_data, 2059  const Range& range, 2060  hid_t idx_table, 2061  size_t table_size, 2062  int /*type_size*/, 2063  const char* name ) 2064 { 2065  ErrorCode rval; 2066  mhdf_Status status; 2067  2068  CHECK_OPEN_HANDLES; 2069  2070  std::string tname( name ? name : "<UNKNOWN TAG?>" ); 2071  tname += " - End Indices"; 2072  IODebugTrack track( debugTrack, tname, table_size ); 2073  2074  // Set up data buffer for writing indices 2075  size_t chunk_size = bufferSize / ( std::max( sizeof( void* ), sizeof( long ) ) + sizeof( int ) ); 2076  mhdf_index_t* idx_buffer = (mhdf_index_t*)dataBuffer; 2077  const void** junk = (const void**)dataBuffer; 2078  int* size_buffer = (int*)( dataBuffer + chunk_size * std::max( sizeof( void* ), sizeof( mhdf_index_t ) ) ); 2079  2080  // Write IDs of tagged entities. 2081  long data_offset = tag_data.var_data_offset - 1; // Offset at which to write data buffer 2082  size_t remaining = range.size(); 2083  size_t offset = tag_data.sparse_offset; 2084  size_t num_writes = ( remaining + chunk_size - 1 ) / chunk_size; 2085  if( tag_data.max_num_ents ) 2086  { 2087  assert( tag_data.max_num_ents >= (unsigned long)remaining ); 2088  num_writes = ( tag_data.max_num_ents + chunk_size - 1 ) / chunk_size; 2089  } 2090  Range::const_iterator iter = range.begin(); 2091  while( remaining ) 2092  { 2093  (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 2094  2095  // Write "chunk_size" blocks of data 2096  size_t count = remaining > chunk_size ? chunk_size : remaining; 2097  remaining -= count; 2098  Range::const_iterator stop = iter; 2099  stop += count; 2100  Range tmp; 2101  tmp.merge( iter, stop ); 2102  iter = stop; 2103  assert( tmp.size() == (unsigned)count ); 2104  2105  rval = iFace->tag_get_by_ptr( tag_data.tag_id, tmp, junk, size_buffer ); 2106  CHK_MB_ERR_0( rval ); 2107  2108  // Calculate end indices 2109  dbgOut.print( 3, " writing var-len tag offset chunk.\n" ); 2110  track.record_io( offset, count ); 2111  for( size_t i = 0; i < count; ++i ) 2112  { 2113  data_offset += size_buffer[i]; 2114  idx_buffer[i] = data_offset; 2115  } 2116  2117  // Write 2118  mhdf_writeSparseTagIndicesWithOpt( idx_table, offset, count, MHDF_INDEX_TYPE, idx_buffer, writeProp, &status ); 2119  CHK_MHDF_ERR_0( status ); 2120  2121  offset += count; 2122  --num_writes; 2123  } // while (remaining) 2124  2125  // Do empty writes if necessary for parallel collective IO 2126  if( collectiveIO ) 2127  { 2128  while( num_writes-- ) 2129  { 2130  assert( writeProp != H5P_DEFAULT ); 2131  dbgOut.print( 3, " writing empty sparse tag entity chunk.\n" ); 2132  mhdf_writeSparseTagIndicesWithOpt( idx_table, offset, 0, id_type, 0, writeProp, &status ); 2133  CHK_MHDF_ERR_0( status ); 2134  } 2135  } 2136  2137  track.all_reduce(); 2138  return MB_SUCCESS; 2139 } 2140  2141 ErrorCode WriteHDF5::write_var_len_data( const TagDesc& tag_data, 2142  const Range& range, 2143  hid_t table, 2144  size_t table_size, 2145  bool handle_tag, 2146  hid_t hdf_type, 2147  int type_size, 2148  const char* name ) 2149 { 2150  ErrorCode rval; 2151  mhdf_Status status; 2152  2153  CHECK_OPEN_HANDLES; 2154  assert( !handle_tag || sizeof( EntityHandle ) == type_size ); 2155  2156  std::string tname( name ? name : "<UNKNOWN TAG?>" ); 2157  tname += " - Values"; 2158  IODebugTrack track( debugTrack, tname, table_size ); 2159  2160  const size_t buffer_size = bufferSize / type_size; 2161  2162  size_t num_writes = ( table_size + buffer_size - 1 ) / buffer_size; 2163  if( collectiveIO ) 2164  { 2165  assert( tag_data.max_num_vals > 0 ); 2166  num_writes = ( tag_data.max_num_vals + buffer_size - 1 ) / buffer_size; 2167  } 2168  2169  unsigned char* buffer = (unsigned char*)dataBuffer; 2170  const void* prev_data = 0; // Data left over from prev iteration 2171  size_t prev_len = 0; 2172  Range::const_iterator iter = range.begin(); 2173  long offset = tag_data.var_data_offset; 2174  while( prev_data || iter != range.end() ) 2175  { 2176  size_t count = 0; 2177  if( prev_data ) 2178  { 2179  size_t len; 2180  const void* ptr = prev_data; 2181  if( prev_len <= buffer_size ) 2182  { 2183  len = prev_len; 2184  prev_data = 0; 2185  prev_len = 0; 2186  } 2187  else 2188  { 2189  len = buffer_size; 2190  prev_data = ( (const char*)prev_data ) + buffer_size * type_size; 2191  prev_len -= buffer_size; 2192  } 2193  2194  if( handle_tag ) 2195  convert_handle_tag( (const EntityHandle*)ptr, (EntityHandle*)buffer, len ); 2196  else 2197  memcpy( buffer, ptr, len * type_size ); 2198  count = len; 2199  } 2200  2201  for( ; count < buffer_size && iter != range.end(); ++iter ) 2202  { 2203  int len; 2204  const void* ptr; 2205  rval = iFace->tag_get_by_ptr( tag_data.tag_id, &*iter, 1, &ptr, &len ); 2206  CHK_MB_ERR_0( rval ); 2207  if( len + count > buffer_size ) 2208  { 2209  prev_len = len + count - buffer_size; 2210  len = buffer_size - count; 2211  prev_data = ( (const char*)ptr ) + len * type_size; 2212  } 2213  2214  if( handle_tag ) 2215  convert_handle_tag( (const EntityHandle*)ptr, ( (EntityHandle*)buffer ) + count, len ); 2216  else 2217  memcpy( buffer + count * type_size, ptr, len * type_size ); 2218  count += len; 2219  } 2220  2221  track.record_io( offset, count ); 2222  mhdf_writeTagValuesWithOpt( table, offset, count, hdf_type, buffer, writeProp, &status ); 2223  offset += count; 2224  CHK_MHDF_ERR_0( status ); 2225  --num_writes; 2226  } 2227  2228  // Do empty writes if necessary for parallel collective IO 2229  if( collectiveIO ) 2230  { 2231  while( num_writes-- ) 2232  { 2233  assert( writeProp != H5P_DEFAULT ); 2234  dbgOut.print( 3, " writing empty var-len tag data chunk.\n" ); 2235  mhdf_writeTagValuesWithOpt( table, 0, 0, hdf_type, 0, writeProp, &status ); 2236  CHK_MHDF_ERR_0( status ); 2237  } 2238  } 2239  2240  track.all_reduce(); 2241  return MB_SUCCESS; 2242 } 2243  2244 ErrorCode WriteHDF5::write_var_len_tag( const TagDesc& tag_data, 2245  const std::string& name, 2246  DataType mb_data_type, 2247  hid_t hdf_type, 2248  int type_size ) 2249 { 2250  ErrorCode rval; 2251  mhdf_Status status; 2252  hid_t tables[3]; 2253  long table_size; 2254  long data_table_size; 2255  2256  CHECK_OPEN_HANDLES; 2257  2258  // Get entities for which to write tag values 2259  Range range; 2260  rval = get_sparse_tagged_entities( tag_data, range ); 2261  2262  // Open tables to write info 2263  mhdf_openSparseTagData( filePtr, name.c_str(), &table_size, &data_table_size, tables, &status ); 2264  CHK_MHDF_ERR_0( status ); 2265  assert( range.size() + tag_data.sparse_offset <= (unsigned long)table_size ); 2266  2267  // Write IDs for tagged entities 2268  subState.start( "writing ids for var-len tag: ", name.c_str() ); 2269  rval = write_sparse_ids( tag_data, range, tables[0], table_size, name.c_str() ); 2270  subState.end( rval ); 2271  CHK_MB_ERR_2( rval, tables, status ); 2272  mhdf_closeData( filePtr, tables[0], &status ); 2273  CHK_MHDF_ERR_2( status, tables + 1 ); 2274  2275  // Write offsets for tagged entities 2276  subState.start( "writing indices for var-len tag: ", name.c_str() ); 2277  rval = write_var_len_indices( tag_data, range, tables[2], table_size, type_size, name.c_str() ); 2278  subState.end( rval ); 2279  CHK_MB_ERR_1( rval, tables[1], status ); 2280  mhdf_closeData( filePtr, tables[2], &status ); 2281  CHK_MHDF_ERR_1( status, tables[1] ); 2282  2283  // Write the actual tag data 2284  subState.start( "writing values for var-len tag: ", name.c_str() ); 2285  rval = write_var_len_data( tag_data, range, tables[1], data_table_size, mb_data_type == MB_TYPE_HANDLE, hdf_type, 2286  type_size, name.c_str() ); 2287  subState.end( rval ); 2288  CHK_MB_ERR_0( rval ); 2289  mhdf_closeData( filePtr, tables[1], &status ); 2290  CHK_MHDF_ERR_0( status ); 2291  2292  return MB_SUCCESS; 2293 } 2294  2295 ErrorCode WriteHDF5::write_dense_tag( const TagDesc& tag_data, 2296  const ExportSet& elem_data, 2297  const std::string& name, 2298  DataType mb_data_type, 2299  hid_t value_type, 2300  int value_type_size ) 2301 { 2302  CHECK_OPEN_HANDLES; 2303  2304  // Open tables to write info 2305  mhdf_Status status; 2306  long table_size; 2307  hid_t table = mhdf_openDenseTagData( filePtr, name.c_str(), elem_data.name(), &table_size, &status ); 2308  CHK_MHDF_ERR_0( status ); 2309  assert( elem_data.range.size() + elem_data.offset <= (unsigned long)table_size ); 2310  2311  IODebugTrack track( debugTrack, name + " " + elem_data.name() + " Data", table_size ); 2312  ErrorCode rval = write_tag_values( tag_data.tag_id, table, elem_data.offset, elem_data.range, mb_data_type, 2313  value_type, value_type_size, elem_data.max_num_ents, track ); 2314  CHK_MB_ERR_0( rval ); 2315  mhdf_closeData( filePtr, table, &status ); 2316  CHK_MHDF_ERR_0( status ); 2317  2318  return MB_SUCCESS; 2319 } 2320  2321 ErrorCode WriteHDF5::write_tag_values( Tag tag_id, 2322  hid_t data_table, 2323  unsigned long offset_in, 2324  const Range& range_in, 2325  DataType mb_data_type, 2326  hid_t value_type, 2327  int value_type_size, 2328  unsigned long max_num_ents, 2329  IODebugTrack& track ) 2330 { 2331  mhdf_Status status; 2332  2333  CHECK_OPEN_HANDLES; 2334  2335  // Set up data buffer for writing tag values 2336  size_t chunk_size = bufferSize / value_type_size; 2337  assert( chunk_size > 0 ); 2338  char* tag_buffer = (char*)dataBuffer; 2339  2340  // Write the tag values 2341  size_t remaining = range_in.size(); 2342  size_t offset = offset_in; 2343  Range::const_iterator iter = range_in.begin(); 2344  long num_writes = ( remaining + chunk_size - 1 ) / chunk_size; 2345  if( max_num_ents ) 2346  { 2347  assert( max_num_ents >= remaining ); 2348  num_writes = ( max_num_ents + chunk_size - 1 ) / chunk_size; 2349  } 2350  while( remaining ) 2351  { 2352  (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 2353  2354  // Write "chunk_size" blocks of data 2355  long count = (unsigned long)remaining > chunk_size ? chunk_size : remaining; 2356  remaining -= count; 2357  memset( tag_buffer, 0, count * value_type_size ); 2358  Range::const_iterator stop = iter; 2359  stop += count; 2360  Range range; 2361  range.merge( iter, stop ); 2362  iter = stop; 2363  assert( range.size() == (unsigned)count ); 2364  2365  ErrorCode rval = iFace->tag_get_data( tag_id, range, tag_buffer ); 2366  CHK_MB_ERR_0( rval ); 2367  2368  // Convert EntityHandles to file ids 2369  if( mb_data_type == MB_TYPE_HANDLE ) 2370  convert_handle_tag( reinterpret_cast< EntityHandle* >( tag_buffer ), 2371  count * value_type_size / sizeof( EntityHandle ) ); 2372  2373  // Write the data 2374  dbgOut.print( 2, " writing tag value chunk.\n" ); 2375  track.record_io( offset, count ); 2376  assert( value_type > 0 ); 2377  mhdf_writeTagValuesWithOpt( data_table, offset, count, value_type, tag_buffer, writeProp, &status ); 2378  CHK_MHDF_ERR_0( status ); 2379  2380  offset += count; 2381  --num_writes; 2382  } // while (remaining) 2383  2384  // Do empty writes if necessary for parallel collective IO 2385  if( collectiveIO ) 2386  { 2387  while( num_writes-- ) 2388  { 2389  assert( writeProp != H5P_DEFAULT ); 2390  dbgOut.print( 2, " writing empty tag value chunk.\n" ); 2391  assert( value_type > 0 ); 2392  mhdf_writeTagValuesWithOpt( data_table, offset, 0, value_type, 0, writeProp, &status ); 2393  CHK_MHDF_ERR_0( status ); 2394  } 2395  } 2396  2397  track.all_reduce(); 2398  return MB_SUCCESS; 2399 } 2400  2401 ErrorCode WriteHDF5::write_qa( const std::vector< std::string >& list ) 2402 { 2403  const char* app = "MOAB"; 2404  const char* vers = MOAB_VERSION; 2405  char date_str[64]; 2406  char time_str[64]; 2407  2408  CHECK_OPEN_HANDLES; 2409  2410  std::vector< const char* > strs( list.size() ? list.size() : 4 ); 2411  if( list.size() == 0 ) 2412  { 2413  time_t t = time( NULL ); 2414  tm* lt = localtime( &t ); 2415 #ifdef WIN32 2416  strftime( date_str, sizeof( date_str ), "%m/%d/%y", lt ); // VS 2008 does not support %D 2417  strftime( time_str, sizeof( time_str ), "%H:%M:%S", lt ); // VS 2008 does not support %T 2418 #else 2419  strftime( date_str, sizeof( date_str ), "%D", lt ); 2420  strftime( time_str, sizeof( time_str ), "%T", lt ); 2421 #endif 2422  2423  strs[0] = app; 2424  strs[1] = vers; 2425  strs[2] = date_str; 2426  strs[3] = time_str; 2427  } 2428  else 2429  { 2430  for( unsigned int i = 0; i < list.size(); ++i ) 2431  strs[i] = list[i].c_str(); 2432  } 2433  2434  mhdf_Status status; 2435  dbgOut.print( 2, " writing QA history.\n" ); 2436  mhdf_writeHistory( filePtr, &strs[0], strs.size(), &status ); 2437  CHK_MHDF_ERR_0( status ); 2438  2439  return MB_SUCCESS; 2440 } 2441  2442 /* 2443 ErrorCode WriteHDF5::register_known_tag_types(Interface* iface) 2444 { 2445  hid_t int4, double16; 2446  hsize_t dim[1]; 2447  int error = 0; 2448  ErrorCode rval; 2449  2450  dim[0] = 4; 2451  int4 = H5Tarray_create(H5T_NATIVE_INT, 1, dim, NULL); 2452  2453  dim[0] = 16; 2454  double16 = H5Tarray_create(H5T_NATIVE_DOUBLE, 1, dim, NULL); 2455  2456  if (int4 < 0 || double16 < 0) 2457  error = 1; 2458  2459  struct { const char* name; hid_t type; } list[] = { 2460  { GLOBAL_ID_TAG_NAME, H5T_NATIVE_INT } , 2461  { MATERIAL_SET_TAG_NAME, H5T_NATIVE_INT }, 2462  { DIRICHLET_SET_TAG_NAME, H5T_NATIVE_INT }, 2463  { NEUMANN_SET_TAG_NAME, H5T_NATIVE_INT }, 2464  { HAS_MID_NODES_TAG_NAME, int4 }, 2465  { GEOM_DIMENSION_TAG_NAME, H5T_NATIVE_INT }, 2466  { MESH_TRANSFORM_TAG_NAME, double16 }, 2467  { 0, 0 } }; 2468  2469  for (int i = 0; list[i].name; ++i) { 2470  if (list[i].type < 1) { 2471  ++error; 2472  continue; 2473  } 2474  2475  Tag handle; 2476  2477  std::string name("__hdf5_tag_type_"); 2478  name += list[i].name; 2479  2480  rval = iface->tag_get_handle(name.c_str(), handle); 2481  if (MB_TAG_NOT_FOUND == rval) { 2482  rval = iface->tag_create(name.c_str(), sizeof(hid_t), MB_TAG_SPARSE, handle, NULL); 2483  if (MB_SUCCESS != rval) { 2484  ++error; 2485  continue; 2486  } 2487  2488  hid_t copy_id = H5Tcopy(list[i].type); 2489  const EntityHandle mesh = 0; 2490  rval = iface->tag_set_data(handle, &mesh, 1, &copy_id); 2491  if (MB_SUCCESS != rval) { 2492  ++error; 2493  continue; 2494  } 2495  } 2496  } 2497  2498  H5Tclose(int4); 2499  H5Tclose(double16); 2500  return error ? MB_FAILURE : MB_SUCCESS; 2501 } 2502 */ 2503  2504 ErrorCode WriteHDF5::gather_tags( const Tag* user_tag_list, int num_tags ) 2505 { 2506  ErrorCode result; 2507  std::vector< Tag > tag_list; 2508  std::vector< Tag >::iterator t_itor; 2509  Range range; 2510  2511  // Get list of Tags to write 2512  result = writeUtil->get_tag_list( tag_list, user_tag_list, num_tags ); 2513  CHK_MB_ERR_0( result ); 2514  2515  // Get list of tags 2516  for( t_itor = tag_list.begin(); t_itor != tag_list.end(); ++t_itor ) 2517  { 2518  // Add tag to export list 2519  TagDesc tag_data; 2520  tag_data.write_sparse = false; 2521  tag_data.tag_id = *t_itor; 2522  tag_data.sparse_offset = 0; 2523  tag_data.var_data_offset = 0; 2524  tag_data.max_num_ents = 0; 2525  tag_data.max_num_vals = 0; 2526  tagList.push_back( tag_data ); 2527  } 2528  2529  return MB_SUCCESS; 2530 } 2531  2532 // If we support parallel, then this function will have been 2533 // overridden with an alternate version in WriteHDF5Parallel 2534 // that supports parallel I/O. If we're here 2535 // then MOAB was not built with support for parallel HDF5 I/O. 2536 ErrorCode WriteHDF5::parallel_create_file( const char* /* filename */, 2537  bool /* overwrite */, 2538  const std::vector< std::string >& /* qa_records */, 2539  const FileOptions& /* opts */, 2540  const Tag* /* tag_list */, 2541  int /* num_tags */, 2542  int /* dimension */, 2543  double* /* times */ ) 2544 { 2545  MB_SET_ERR( MB_NOT_IMPLEMENTED, "WriteHDF5 does not support parallel writing" ); 2546 } 2547  2548 ErrorCode WriteHDF5::serial_create_file( const char* filename, 2549  bool overwrite, 2550  const std::vector< std::string >& qa_records, 2551  const Tag* user_tag_list, 2552  int num_user_tags, 2553  int dimension ) 2554 { 2555  long first_id; 2556  mhdf_Status status; 2557  hid_t handle; 2558  std::list< ExportSet >::iterator ex_itor; 2559  ErrorCode rval; 2560  2561  topState.start( "creating file" ); 2562  2563  const char* type_names[MBMAXTYPE]; 2564  memset( type_names, 0, MBMAXTYPE * sizeof( char* ) ); 2565  for( EntityType i = MBEDGE; i < MBENTITYSET; ++i ) 2566  type_names[i] = CN::EntityTypeName( i ); 2567  2568  // Create the file 2569  filePtr = mhdf_createFile( filename, overwrite, type_names, MBMAXTYPE, id_type, &status ); 2570  CHK_MHDF_ERR_0( status ); 2571  assert( !!filePtr ); 2572  2573  rval = write_qa( qa_records ); 2574  CHK_MB_ERR_0( rval ); 2575  2576  // Create node table 2577  if( nodeSet.range.size() ) 2578  { 2579  nodeSet.total_num_ents = nodeSet.range.size(); 2580  handle = mhdf_createNodeCoords( filePtr, dimension, nodeSet.total_num_ents, &first_id, &status ); 2581  CHK_MHDF_ERR_0( status ); 2582  mhdf_closeData( filePtr, handle, &status ); 2583  CHK_MHDF_ERR_0( status ); 2584  nodeSet.first_id = (wid_t)first_id; 2585  rval = assign_ids( nodeSet.range, nodeSet.first_id ); 2586  CHK_MB_ERR_0( rval ); 2587  } 2588  else 2589  { 2590  nodeSet.first_id = std::numeric_limits< wid_t >::max(); 2591  } 2592  nodeSet.offset = 0; 2593  2594  // Create element tables 2595  for( ex_itor = exportList.begin(); ex_itor != exportList.end(); ++ex_itor ) 2596  { 2597  ex_itor->total_num_ents = ex_itor->range.size(); 2598  rval = create_elem_table( *ex_itor, ex_itor->total_num_ents, first_id ); 2599  CHK_MB_ERR_0( rval ); 2600  2601  ex_itor->first_id = (wid_t)first_id; 2602  ex_itor->offset = 0; 2603  rval = assign_ids( ex_itor->range, ex_itor->first_id ); 2604  CHK_MB_ERR_0( rval ); 2605  } 2606  // Create set tables 2607  writeSets = !setSet.range.empty(); 2608  if( writeSets ) 2609  { 2610  long contents_len, children_len, parents_len; 2611  2612  setSet.total_num_ents = setSet.range.size(); 2613  setSet.max_num_ents = setSet.total_num_ents; 2614  rval = create_set_meta( setSet.total_num_ents, first_id ); 2615  CHK_MB_ERR_0( rval ); 2616  2617  setSet.first_id = (wid_t)first_id; 2618  rval = assign_ids( setSet.range, setSet.first_id ); 2619  CHK_MB_ERR_0( rval ); 2620  2621  rval = count_set_size( setSet.range, contents_len, children_len, parents_len ); 2622  CHK_MB_ERR_0( rval ); 2623  2624  rval = create_set_tables( contents_len, children_len, parents_len ); 2625  CHK_MB_ERR_0( rval ); 2626  2627  setSet.offset = 0; 2628  setContentsOffset = 0; 2629  setChildrenOffset = 0; 2630  setParentsOffset = 0; 2631  writeSetContents = !!contents_len; 2632  writeSetChildren = !!children_len; 2633  writeSetParents = !!parents_len; 2634  2635  maxNumSetContents = contents_len; 2636  maxNumSetChildren = children_len; 2637  maxNumSetParents = parents_len; 2638  } // if (!setSet.range.empty()) 2639  2640  // Create adjacency table after set table, because sets do not have yet an id 2641  // some entities are adjacent to sets (exodus?) 2642  // Create node adjacency table 2643  wid_t num_adjacencies; 2644 #ifdef MB_H5M_WRITE_NODE_ADJACENCIES 2645  rval = count_adjacencies( nodeSet.range, num_adjacencies ); 2646  CHK_MB_ERR_0( rval ); 2647  nodeSet.adj_offset = 0; 2648  nodeSet.max_num_adjs = num_adjacencies; 2649  if( num_adjacencies > 0 ) 2650  { 2651  handle = mhdf_createAdjacency( filePtr, mhdf_node_type_handle(), num_adjacencies, &status ); 2652  CHK_MHDF_ERR_0( status ); 2653  mhdf_closeData( filePtr, handle, &status ); 2654  } 2655 #endif 2656  2657  // Create element adjacency tables 2658  for( ex_itor = exportList.begin(); ex_itor != exportList.end(); ++ex_itor ) 2659  { 2660  rval = count_adjacencies( ex_itor->range, num_adjacencies ); 2661  CHK_MB_ERR_0( rval ); 2662  2663  ex_itor->adj_offset = 0; 2664  ex_itor->max_num_adjs = num_adjacencies; 2665  if( num_adjacencies > 0 ) 2666  { 2667  handle = mhdf_createAdjacency( filePtr, ex_itor->name(), num_adjacencies, &status ); 2668  CHK_MHDF_ERR_0( status ); 2669  mhdf_closeData( filePtr, handle, &status ); 2670  } 2671  } 2672  2673  dbgOut.tprint( 1, "Gathering Tags\n" ); 2674  2675  rval = gather_tags( user_tag_list, num_user_tags ); 2676  CHK_MB_ERR_0( rval ); 2677  2678  // Create the tags and tag data tables 2679  std::list< TagDesc >::iterator tag_iter = tagList.begin(); 2680  for( ; tag_iter != tagList.end(); ++tag_iter ) 2681  { 2682  // As we haven't yet added any ExportSets for which to write 2683  // dense tag data to the TagDesc struct pointed to by 2684  // tag_iter, this call will initially return all tagged entities 2685  // in the set of entities to be written. 2686  Range range; 2687  rval = get_sparse_tagged_entities( *tag_iter, range ); 2688  CHK_MB_ERR_0( rval ); 2689  2690  int s; 2691  bool var_len = ( MB_VARIABLE_DATA_LENGTH == iFace->tag_get_length( tag_iter->tag_id, s ) ); 2692  2693  // Determine which ExportSets we want to write dense 2694  // data for. We never write dense data for variable-length 2695  // tag data. 2696  if( !var_len && writeTagDense ) 2697  { 2698  // Check if we want to write this tag in dense format even if not 2699  // all of the entities have a tag value. The criterion of this 2700  // is that the tag be dense, have a default value, and have at 2701  // least 2/3 of the entities tagged. 2702  bool prefer_dense = false; 2703  TagType type; 2704  rval = iFace->tag_get_type( tag_iter->tag_id, type ); 2705  CHK_MB_ERR_0( rval ); 2706  if( MB_TAG_DENSE == type ) 2707  { 2708  const void* defval = 0; 2709  rval = iFace->tag_get_default_value( tag_iter->tag_id, defval, s ); 2710  if( MB_SUCCESS == rval ) prefer_dense = true; 2711  } 2712  2713  if( check_dense_format_tag( nodeSet, range, prefer_dense ) ) 2714  { 2715  range -= nodeSet.range; 2716  tag_iter->dense_list.push_back( nodeSet ); 2717  } 2718  2719  std::list< ExportSet >::const_iterator ex = exportList.begin(); 2720  for( ; ex != exportList.end(); ++ex ) 2721  { 2722  if( check_dense_format_tag( *ex, range, prefer_dense ) ) 2723  { 2724  range -= ex->range; 2725  tag_iter->dense_list.push_back( *ex ); 2726  } 2727  } 2728  2729  if( check_dense_format_tag( setSet, range, prefer_dense ) ) 2730  { 2731  range -= setSet.range; 2732  tag_iter->dense_list.push_back( setSet ); 2733  } 2734  } 2735  2736  tag_iter->write_sparse = !range.empty(); 2737  2738  unsigned long var_len_total = 0; 2739  if( var_len ) 2740  { 2741  rval = get_tag_data_length( *tag_iter, range, var_len_total ); 2742  CHK_MB_ERR_0( rval ); 2743  } 2744  2745  rval = create_tag( *tag_iter, range.size(), var_len_total ); 2746  CHK_MB_ERR_0( rval ); 2747  } // for (tags) 2748  2749  topState.end(); 2750  return MB_SUCCESS; 2751 } 2752  2753 bool WriteHDF5::check_dense_format_tag( const ExportSet& ents, const Range& all_tagged, bool prefer_dense ) 2754 { 2755  // If there are no tagged entities, then don't write anything 2756  if( ents.range.empty() ) return false; 2757  2758  // If all of the entities are tagged, then write in dense format 2759  if( all_tagged.contains( ents.range ) ) return true; 2760  2761  // Unless asked for more lenient choice of dense format, return false 2762  if( !prefer_dense ) return false; 2763  2764  // If we're being lenient about choosing dense format, then 2765  // return true if at least 2/3 of the entities are tagged. 2766  Range xsect = intersect( setSet.range, all_tagged ); 2767  if( 3 * xsect.size() >= 2 * setSet.range.size() ) return true; 2768  2769  return false; 2770 } 2771  2772 ErrorCode WriteHDF5::count_adjacencies( const Range& set, wid_t& result ) 2773 { 2774  ErrorCode rval; 2775  std::vector< wid_t > adj_list; 2776  Range::const_iterator iter = set.begin(); 2777  const Range::const_iterator end = set.end(); 2778  result = 0; 2779  for( ; iter != end; ++iter ) 2780  { 2781  adj_list.clear(); 2782  rval = get_adjacencies( *iter, adj_list ); 2783  CHK_MB_ERR_0( rval ); 2784  2785  if( adj_list.size() > 0 ) result += 2 + adj_list.size(); 2786  } 2787  2788  return MB_SUCCESS; 2789 } 2790  2791 ErrorCode WriteHDF5::create_elem_table( const ExportSet& block, long num_entities, long& first_id_out ) 2792 { 2793  mhdf_Status status; 2794  hid_t handle; 2795  2796  CHECK_OPEN_HANDLES; 2797  2798  mhdf_addElement( filePtr, block.name(), block.type, &status ); 2799  CHK_MHDF_ERR_0( status ); 2800  2801  handle = mhdf_createConnectivity( filePtr, block.name(), block.num_nodes, num_entities, &first_id_out, &status ); 2802  CHK_MHDF_ERR_0( status ); 2803  mhdf_closeData( filePtr, handle, &status ); 2804  CHK_MHDF_ERR_0( status ); 2805  2806  return MB_SUCCESS; 2807 } 2808  2809 ErrorCode WriteHDF5::count_set_size( const Range& sets, 2810  long& contents_length_out, 2811  long& children_length_out, 2812  long& parents_length_out ) 2813 { 2814  ErrorCode rval; 2815  Range set_contents; 2816  long contents_length_set, children_length_set, parents_length_set; 2817  unsigned long flags; 2818  std::vector< wid_t > set_contents_ids; 2819  std::vector< SpecialSetData >::const_iterator si = specialSets.begin(); 2820  2821  contents_length_out = 0; 2822  children_length_out = 0; 2823  parents_length_out = 0; 2824  2825  for( Range::const_iterator iter = sets.begin(); iter != sets.end(); ++iter ) 2826  { 2827  while( si != specialSets.end() && si->setHandle < *iter ) 2828  ++si; 2829  2830  if( si != specialSets.end() && si->setHandle == *iter ) 2831  { 2832  contents_length_out += si->contentIds.size(); 2833  children_length_out += si->childIds.size(); 2834  parents_length_out += si->parentIds.size(); 2835  ++si; 2836  continue; 2837  } 2838  2839  rval = get_set_info( *iter, contents_length_set, children_length_set, parents_length_set, flags ); 2840  CHK_MB_ERR_0( rval ); 2841  2842  // Check if can and should compress as ranges 2843  if( !( flags & MESHSET_ORDERED ) && contents_length_set ) 2844  { 2845  set_contents.clear(); 2846  rval = iFace->get_entities_by_handle( *iter, set_contents, false ); 2847  CHK_MB_ERR_0( rval ); 2848  2849  bool blocked_list; 2850  rval = range_to_blocked_list( set_contents, set_contents_ids, blocked_list ); 2851  CHK_MB_ERR_0( rval ); 2852  2853  if( blocked_list ) 2854  { 2855  assert( set_contents_ids.size() % 2 == 0 ); 2856  contents_length_set = set_contents_ids.size(); 2857  } 2858  } 2859  2860  contents_length_out += contents_length_set; 2861  children_length_out += children_length_set; 2862  parents_length_out += parents_length_set; 2863  } 2864  2865  return MB_SUCCESS; 2866 } 2867  2868 ErrorCode WriteHDF5::create_set_meta( long num_sets, long& first_id_out ) 2869 { 2870  hid_t handle; 2871  mhdf_Status status; 2872  2873  CHECK_OPEN_HANDLES; 2874  2875  handle = mhdf_createSetMeta( filePtr, num_sets, &first_id_out, &status ); 2876  CHK_MHDF_ERR_0( status ); 2877  mhdf_closeData( filePtr, handle, &status ); 2878  2879  return MB_SUCCESS; 2880 } 2881  2882 WriteHDF5::SpecialSetData* WriteHDF5::find_set_data( EntityHandle h ) 2883 { 2884  SpecialSetData tmp; 2885  tmp.setHandle = h; 2886  std::vector< SpecialSetData >::iterator i; 2887  i = std::lower_bound( specialSets.begin(), specialSets.end(), tmp, SpecSetLess() ); 2888  return ( i == specialSets.end() || i->setHandle != h ) ? 0 : &*i; 2889 } 2890  2891 ErrorCode WriteHDF5::create_set_tables( long num_set_contents, long num_set_children, long num_set_parents ) 2892 { 2893  hid_t handle; 2894  mhdf_Status status; 2895  2896  CHECK_OPEN_HANDLES; 2897  2898  if( num_set_contents > 0 ) 2899  { 2900  handle = mhdf_createSetData( filePtr, num_set_contents, &status ); 2901  CHK_MHDF_ERR_0( status ); 2902  mhdf_closeData( filePtr, handle, &status ); 2903  } 2904  2905  if( num_set_children > 0 ) 2906  { 2907  handle = mhdf_createSetChildren( filePtr, num_set_children, &status ); 2908  CHK_MHDF_ERR_0( status ); 2909  mhdf_closeData( filePtr, handle, &status ); 2910  } 2911  2912  if( num_set_parents > 0 ) 2913  { 2914  handle = mhdf_createSetParents( filePtr, num_set_parents, &status ); 2915  CHK_MHDF_ERR_0( status ); 2916  mhdf_closeData( filePtr, handle, &status ); 2917  } 2918  2919  return MB_SUCCESS; 2920 } 2921  2922 ErrorCode WriteHDF5::get_tag_size( Tag tag, 2923  DataType& moab_type, 2924  int& num_bytes, 2925  int& type_size, 2926  int& array_length, 2927  mhdf_TagDataType& file_type, 2928  hid_t& hdf_type ) 2929 { 2930  ErrorCode rval; 2931  Tag type_handle; 2932  std::string tag_name, tag_type_name; 2933  2934  CHECK_OPEN_HANDLES; 2935  2936  // We return NULL for hdf_type if it can be determined from 2937  // the file_type. The only case where it is non-zero is 2938  // if the user specified a specific type via a mesh tag. 2939  hdf_type = (hid_t)0; 2940  bool close_hdf_type = false; 2941  2942  rval = iFace->tag_get_data_type( tag, moab_type ); 2943  CHK_MB_ERR_0( rval ); 2944  rval = iFace->tag_get_length( tag, array_length ); 2945  if( MB_VARIABLE_DATA_LENGTH == rval ) 2946  { 2947  array_length = MB_VARIABLE_LENGTH; 2948  } 2949  else if( MB_SUCCESS != rval ) 2950  return error( rval ); 2951  rval = iFace->tag_get_bytes( tag, num_bytes ); 2952  if( MB_VARIABLE_DATA_LENGTH == rval ) 2953  num_bytes = MB_VARIABLE_LENGTH; 2954  else if( MB_SUCCESS != rval ) 2955  return error( rval ); 2956  2957  switch( moab_type ) 2958  { 2959  case MB_TYPE_INTEGER: 2960  type_size = sizeof( int ); 2961  file_type = mhdf_INTEGER; 2962  hdf_type = H5T_NATIVE_INT; 2963  close_hdf_type = false; 2964  break; 2965  case MB_TYPE_DOUBLE: 2966  type_size = sizeof( double ); 2967  file_type = mhdf_FLOAT; 2968  hdf_type = H5T_NATIVE_DOUBLE; 2969  close_hdf_type = false; 2970  break; 2971  case MB_TYPE_BIT: 2972  type_size = sizeof( bool ); 2973  file_type = mhdf_BITFIELD; 2974  assert( array_length <= 8 ); 2975  hdf_type = H5Tcopy( H5T_NATIVE_B8 ); 2976  H5Tset_precision( hdf_type, array_length ); 2977  close_hdf_type = true; 2978  break; 2979  case MB_TYPE_HANDLE: 2980  type_size = sizeof( EntityHandle ); 2981  file_type = mhdf_ENTITY_ID; 2982  hdf_type = id_type; 2983  close_hdf_type = false; 2984  break; 2985  case MB_TYPE_OPAQUE: 2986  file_type = mhdf_OPAQUE; 2987  rval = iFace->tag_get_name( tag, tag_name ); 2988  CHK_MB_ERR_0( rval ); 2989  tag_type_name = "__hdf5_tag_type_"; 2990  tag_type_name += tag_name; 2991  rval = iFace->tag_get_handle( tag_type_name.c_str(), 0, MB_TYPE_OPAQUE, type_handle, MB_TAG_ANY ); 2992  if( MB_TAG_NOT_FOUND == rval ) 2993  { 2994  if( num_bytes == MB_VARIABLE_LENGTH ) 2995  type_size = 1; 2996  else 2997  type_size = num_bytes; 2998  hdf_type = H5Tcreate( H5T_OPAQUE, type_size ); 2999  close_hdf_type = true; 3000  } 3001  else if( MB_SUCCESS == rval ) 3002  { 3003  int hsize; 3004  rval = iFace->tag_get_bytes( type_handle, hsize ); 3005  if( hsize != sizeof( hid_t ) ) return error( MB_FAILURE ); 3006  3007  const EntityHandle root = 0; 3008  rval = iFace->tag_get_data( type_handle, &root, 1, &hdf_type ); 3009  if( rval != MB_SUCCESS ) return error( rval ); 3010  3011  type_size = H5Tget_size( hdf_type ); 3012  if( type_size != num_bytes ) return error( MB_FAILURE ); 3013  3014  close_hdf_type = false; 3015  } 3016  else 3017  return error( rval ); 3018  num_bytes = array_length; 3019  array_length = ( num_bytes == MB_VARIABLE_LENGTH ) ? MB_VARIABLE_LENGTH : 1; 3020  break; 3021  default: 3022  break; 3023  } 3024  3025  assert( num_bytes == MB_VARIABLE_LENGTH || ( moab_type == MB_TYPE_BIT && num_bytes == 1 ) || 3026  array_length * type_size == num_bytes ); 3027  3028  if( num_bytes == MB_VARIABLE_LENGTH ) 3029  { 3030  array_length = MB_VARIABLE_LENGTH; 3031  if( !close_hdf_type ) 3032  { 3033  hdf_type = H5Tcopy( hdf_type ); 3034  // close_hdf_type = true; 3035  } 3036  } 3037  else if( array_length > 1 && moab_type != MB_TYPE_BIT ) 3038  { 3039  hsize_t len = array_length; 3040 #if defined( H5Tarray_create_vers ) && ( H5Tarray_create_vers > 1 ) 3041  hid_t temp_id = H5Tarray_create2( hdf_type, 1, &len ); 3042 #else 3043  hid_t temp_id = H5Tarray_create( hdf_type, 1, &len, NULL ); 3044 #endif 3045  if( close_hdf_type ) H5Tclose( hdf_type ); 3046  hdf_type = temp_id; 3047  } 3048  else if( !close_hdf_type ) 3049  { 3050  hdf_type = H5Tcopy( hdf_type ); 3051  // close_hdf_type = true; 3052  } 3053  3054  return MB_SUCCESS; 3055 } 3056  3057 ErrorCode WriteHDF5::get_tag_data_length( const TagDesc& tag_info, const Range& range, unsigned long& result ) 3058 { 3059  ErrorCode rval; 3060  result = 0; 3061  3062  // Split buffer into two pieces, one for pointers and one for sizes 3063  size_t step, remaining; 3064  step = bufferSize / ( sizeof( int ) + sizeof( void* ) ); 3065  const void** ptr_buffer = reinterpret_cast< const void** >( dataBuffer ); 3066  int* size_buffer = reinterpret_cast< int* >( ptr_buffer + step ); 3067  Range subrange; 3068  Range::const_iterator iter = range.begin(); 3069  for( remaining = range.size(); remaining >= step; remaining -= step ) 3070  { 3071  // Get subset of range containing 'count' entities 3072  Range::const_iterator end = iter; 3073  end += step; 3074  subrange.clear(); 3075  subrange.merge( iter, end ); 3076  iter = end; 3077  // Get tag sizes for entities 3078  rval = iFace->tag_get_by_ptr( tag_info.tag_id, subrange, ptr_buffer, size_buffer ); 3079  if( MB_SUCCESS != rval ) return error( rval ); 3080  // Sum lengths 3081  for( size_t i = 0; i < step; ++i ) 3082  result += size_buffer[i]; 3083  } 3084  // Process remaining 3085  subrange.clear(); 3086  subrange.merge( iter, range.end() ); 3087  assert( subrange.size() == remaining ); 3088  rval = iFace->tag_get_by_ptr( tag_info.tag_id, subrange, ptr_buffer, size_buffer ); 3089  if( MB_SUCCESS != rval ) return error( rval ); 3090  for( size_t i = 0; i < remaining; ++i ) 3091  result += size_buffer[i]; 3092  3093  return MB_SUCCESS; 3094 } 3095  3096 ErrorCode WriteHDF5::create_tag( const TagDesc& tag_data, 3097  unsigned long num_sparse_entities, 3098  unsigned long data_table_size ) 3099 { 3100  TagType mb_storage; 3101  DataType mb_type; 3102  mhdf_TagDataType mhdf_type; 3103  int tag_bytes, type_size, num_vals, storage; 3104  hid_t hdf_type = (hid_t)0; 3105  hid_t handles[3]; 3106  std::string tag_name; 3107  ErrorCode rval; 3108  mhdf_Status status; 3109  3110  CHECK_OPEN_HANDLES; 3111  3112  // Get tag properties 3113  rval = iFace->tag_get_type( tag_data.tag_id, mb_storage ); 3114  CHK_MB_ERR_0( rval ); 3115  switch( mb_storage ) 3116  { 3117  case MB_TAG_DENSE: 3118  storage = mhdf_DENSE_TYPE; 3119  break; 3120  case MB_TAG_SPARSE: 3121  storage = mhdf_SPARSE_TYPE; 3122  break; 3123  case MB_TAG_BIT: 3124  storage = mhdf_BIT_TYPE; 3125  break; 3126  case MB_TAG_MESH: 3127  storage = mhdf_MESH_TYPE; 3128  break; 3129  default: 3130  return error( MB_FAILURE ); 3131  } 3132  rval = iFace->tag_get_name( tag_data.tag_id, tag_name ); 3133  CHK_MB_ERR_0( rval ); 3134  rval = get_tag_size( tag_data.tag_id, mb_type, tag_bytes, type_size, num_vals, mhdf_type, hdf_type ); 3135  CHK_MB_ERR_0( rval ); 3136  3137  // Get default value 3138  const void *def_value, *mesh_value; 3139  int def_val_len, mesh_val_len; 3140  rval = iFace->tag_get_default_value( tag_data.tag_id, def_value, def_val_len ); 3141  if( MB_ENTITY_NOT_FOUND == rval ) 3142  { 3143  def_value = 0; 3144  def_val_len = 0; 3145  } 3146  else if( MB_SUCCESS != rval ) 3147  { 3148  H5Tclose( hdf_type ); 3149  return error( rval ); 3150  } 3151  3152  // Get mesh value 3153  unsigned char byte; 3154  const EntityHandle root = 0; 3155  if( mb_storage == MB_TAG_BIT ) 3156  { 3157  rval = iFace->tag_get_data( tag_data.tag_id, &root, 1, &byte ); 3158  mesh_value = &byte; 3159  mesh_val_len = 1; 3160  } 3161  else 3162  { 3163  rval = iFace->tag_get_by_ptr( tag_data.tag_id, &root, 1, &mesh_value, &mesh_val_len ); 3164  } 3165  if( MB_TAG_NOT_FOUND == rval ) 3166  { 3167  mesh_value = 0; 3168  mesh_val_len = 0; 3169  } 3170  else if( MB_SUCCESS != rval ) 3171  { 3172  H5Tclose( hdf_type ); 3173  return error( rval ); 3174  } 3175  3176  // For handle-type tags, need to convert from handles to file ids 3177  if( MB_TYPE_HANDLE == mb_type ) 3178  { 3179  // Make sure there's room in the buffer for both 3180  assert( ( def_val_len + mesh_val_len ) * sizeof( long ) < (size_t)bufferSize ); 3181  3182  // Convert default value 3183  if( def_value ) 3184  { 3185  memcpy( dataBuffer, def_value, def_val_len * sizeof( EntityHandle ) ); 3186  convert_handle_tag( reinterpret_cast< EntityHandle* >( dataBuffer ), def_val_len ); 3187  def_value = dataBuffer; 3188  } 3189  3190  // Convert mesh value 3191  if( mesh_value ) 3192  { 3193  EntityHandle* ptr = reinterpret_cast< EntityHandle* >( dataBuffer ) + def_val_len; 3194  memcpy( ptr, mesh_value, mesh_val_len * sizeof( EntityHandle ) ); 3195  if( convert_handle_tag( ptr, mesh_val_len ) ) 3196  mesh_value = ptr; 3197  else 3198  mesh_value = 0; 3199  } 3200  } 3201  3202  if( MB_VARIABLE_LENGTH != tag_bytes ) 3203  { 3204  // Write the tag description to the file 3205  mhdf_createTag( filePtr, tag_name.c_str(), mhdf_type, num_vals, storage, def_value, mesh_value, hdf_type, 3206  mb_type == MB_TYPE_HANDLE ? id_type : 0, &status ); 3207  CHK_MHDF_ERR_0( status ); 3208  H5Tclose( hdf_type ); 3209  3210  // Create empty table for tag data 3211  if( num_sparse_entities ) 3212  { 3213  mhdf_createSparseTagData( filePtr, tag_name.c_str(), num_sparse_entities, handles, &status ); 3214  CHK_MHDF_ERR_0( status ); 3215  mhdf_closeData( filePtr, handles[0], &status ); 3216  mhdf_closeData( filePtr, handles[1], &status ); 3217  } 3218  3219  for( size_t i = 0; i < tag_data.dense_list.size(); ++i ) 3220  { 3221  const ExportSet* ex = find( tag_data.dense_list[i] ); 3222  assert( 0 != ex ); 3223  handles[0] = mhdf_createDenseTagData( filePtr, tag_name.c_str(), ex->name(), ex->total_num_ents, &status ); 3224  CHK_MHDF_ERR_0( status ); 3225  mhdf_closeData( filePtr, handles[0], &status ); 3226  } 3227  } 3228  else 3229  { 3230  mhdf_createVarLenTag( filePtr, tag_name.c_str(), mhdf_type, storage, def_value, def_val_len, mesh_value, 3231  mesh_val_len, hdf_type, mb_type == MB_TYPE_HANDLE ? id_type : 0, &status ); 3232  CHK_MHDF_ERR_0( status ); 3233  H5Tclose( hdf_type ); 3234  3235  // Create empty table for tag data 3236  if( num_sparse_entities ) 3237  { 3238  mhdf_createVarLenTagData( filePtr, tag_name.c_str(), num_sparse_entities, data_table_size, handles, 3239  &status ); 3240  CHK_MHDF_ERR_0( status ); 3241  mhdf_closeData( filePtr, handles[0], &status ); 3242  mhdf_closeData( filePtr, handles[1], &status ); 3243  mhdf_closeData( filePtr, handles[2], &status ); 3244  } 3245  } 3246  3247  return MB_SUCCESS; 3248 } 3249  3250 ErrorCode WriteHDF5::get_num_sparse_tagged_entities( const TagDesc& tag, size_t& count ) 3251 { 3252  Range tmp; 3253  ErrorCode rval = get_sparse_tagged_entities( tag, tmp ); 3254  count = tmp.size(); 3255  return rval; 3256 } 3257  3258 ErrorCode WriteHDF5::get_sparse_tagged_entities( const TagDesc& tag, Range& results ) 3259 { 3260  results.clear(); 3261  if( !tag.have_dense( setSet ) ) results.merge( setSet.range ); 3262  std::list< ExportSet >::reverse_iterator e; 3263  for( e = exportList.rbegin(); e != exportList.rend(); ++e ) 3264  { 3265  if( !tag.have_dense( *e ) ) results.merge( e->range ); 3266  } 3267  if( !tag.have_dense( nodeSet ) ) results.merge( nodeSet.range ); 3268  if( results.empty() ) return MB_SUCCESS; 3269  3270  return iFace->get_entities_by_type_and_tag( 0, MBMAXTYPE, &tag.tag_id, 0, 1, results, Interface::INTERSECT ); 3271 } 3272  3273 void WriteHDF5::get_write_entities( Range& range ) 3274 { 3275  range.clear(); 3276  range.merge( setSet.range ); 3277  std::list< ExportSet >::reverse_iterator e; 3278  for( e = exportList.rbegin(); e != exportList.rend(); ++e ) 3279  range.merge( e->range ); 3280  range.merge( nodeSet.range ); 3281 } 3282  3283 void WriteHDF5::print_id_map() const 3284 { 3285  print_id_map( std::cout, "" ); 3286 } 3287  3288 void WriteHDF5::print_id_map( std::ostream& s, const char* pfx ) const 3289 { 3290  RangeMap< EntityHandle, wid_t >::const_iterator i; 3291  for( i = idMap.begin(); i != idMap.end(); ++i ) 3292  { 3293  const char* n1 = CN::EntityTypeName( TYPE_FROM_HANDLE( i->begin ) ); 3294  EntityID id = ID_FROM_HANDLE( i->begin ); 3295  if( 1 == i->count ) 3296  { 3297  s << pfx << n1 << " " << id << " -> " << i->value << std::endl; 3298  } 3299  else 3300  { 3301  const char* n2 = CN::EntityTypeName( TYPE_FROM_HANDLE( i->begin + i->count - 1 ) ); 3302  if( n1 == n2 ) 3303  { 3304  s << pfx << n1 << " " << id << "-" << id + i->count - 1 << " -> " << i->value << "-" 3305  << i->value + i->count - 1 << std::endl; 3306  } 3307  else 3308  { 3309  s << pfx << n1 << " " << id << "-" << n1 << " " << ID_FROM_HANDLE( i->begin + i->count - 1 ) << " -> " 3310  << i->value << "-" << i->value + i->count - 1 << std::endl; 3311  } 3312  } 3313  } 3314 } 3315  3316 void WriteHDF5::print_times( const double* t ) const 3317 { 3318  std::cout << "WriteHDF5: " << t[TOTAL_TIME] << std::endl 3319  << " gather mesh: " << t[GATHER_TIME] << std::endl 3320  << " create file: " << t[CREATE_TIME] << std::endl 3321  << " create nodes: " << t[CREATE_NODE_TIME] << std::endl 3322  << " negotiate types: " << t[NEGOTIATE_TYPES_TIME] << std::endl 3323  << " create elem: " << t[CREATE_ELEM_TIME] << std::endl 3324  << " file id exch: " << t[FILEID_EXCHANGE_TIME] << std::endl 3325  << " create adj: " << t[CREATE_ADJ_TIME] << std::endl 3326  << " create set: " << t[CREATE_SET_TIME] << std::endl 3327  << " shared ids: " << t[SHARED_SET_IDS] << std::endl 3328  << " shared data: " << t[SHARED_SET_CONTENTS] << std::endl 3329  << " set offsets: " << t[SET_OFFSET_TIME] << std::endl 3330  << " create tags: " << t[CREATE_TAG_TIME] << std::endl 3331  << " coordinates: " << t[COORD_TIME] << std::endl 3332  << " connectivity: " << t[CONN_TIME] << std::endl 3333  << " sets: " << t[SET_TIME] << std::endl 3334  << " set descrip: " << t[SET_META] << std::endl 3335  << " set content: " << t[SET_CONTENT] << std::endl 3336  << " set parent: " << t[SET_PARENT] << std::endl 3337  << " set child: " << t[SET_CHILD] << std::endl 3338  << " adjacencies: " << t[ADJ_TIME] << std::endl 3339  << " tags: " << t[TAG_TIME] << std::endl 3340  << " dense data: " << t[DENSE_TAG_TIME] << std::endl 3341  << " sparse data: " << t[SPARSE_TAG_TIME] << std::endl 3342  << " var-len data: " << t[VARLEN_TAG_TIME] << std::endl; 3343 } 3344  3345 } // namespace moab