Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
ReadHDF5.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 : ReadHDF5.cpp
18 //
19 // Purpose : HDF5 Writer
20 //
21 // Creator : Jason Kraftcheck
22 //
23 // Creation Date : 04/18/04
24 //-------------------------------------------------------------------------
25 
26 #include <cassert>
27 #include "moab/MOABConfig.h"
28 /* Include our MPI header before any HDF5 because otherwise
29  it will get included indirectly by HDF5 */
30 #ifdef MOAB_HAVE_MPI
31 #include "moab_mpi.h"
32 #include "moab/ParallelComm.hpp"
33 #endif
34 #include <H5Tpublic.h>
35 #include <H5Ppublic.h>
36 #include <H5Epublic.h>
37 #include "moab/Interface.hpp"
38 #include "Internals.hpp"
39 #include "MBTagConventions.hpp"
40 #include "ReadHDF5.hpp"
41 #include "moab/CN.hpp"
42 #include "moab/FileOptions.hpp"
43 #include "moab/CpuTimer.hpp"
44 #ifdef MOAB_HAVE_HDF5_PARALLEL
45 #include <H5FDmpi.h>
46 #include <H5FDmpio.h>
47 #endif
48 //#include "WriteHDF5.hpp"
49 
50 #include <cstdlib>
51 #include <cstring>
52 #include <limits>
53 #include <functional>
54 #include <iostream>
55 
56 #include "IODebugTrack.hpp"
57 #include "ReadHDF5Dataset.hpp"
58 #include "ReadHDF5VarLen.hpp"
59 #include "moab_mpe.h"
60 
61 namespace moab
62 {
63 
64 /* If true, coordinates are read in blocked format (all X values before
65  * Y values before Z values.) If undefined, then all coordinates for a
66  * given vertex are read at the same time.
67  */
68 const bool DEFAULT_BLOCKED_COORDINATE_IO = false;
69 
70 /* If true, file is opened first by root node only to read summary,
71  * file is the closed and the summary is broadcast to all nodes, after
72  * which all nodes open file in parallel to read data. If undefined,
73  * file is opened once in parallel and all nodes read summary data.
74  */
75 const bool DEFAULT_BCAST_SUMMARY = true;
76 
77 /* If true and all processors are to read the same block of data,
78  * read it on one and broadcast to others rather than using collective
79  * io
80  */
82 
83 #define READ_HDF5_BUFFER_SIZE ( 128 * 1024 * 1024 )
84 
85 #define assert_range( PTR, CNT ) \
86  assert( ( PTR ) >= (void*)dataBuffer ); \
87  assert( ( ( PTR ) + ( CNT ) ) <= (void*)( dataBuffer + bufferSize ) );
88 
89 // Call \c error function during HDF5 library errors to make
90 // it easier to trap such errors in the debugger. This function
91 // gets registered with the HDF5 library as a callback. It
92 // works the same as the default (H5Eprint), except that it
93 // also calls the \c error function as a no-op.
94 #if defined( H5E_auto_t_vers ) && H5E_auto_t_vers > 1
95 static herr_t handle_hdf5_error( hid_t stack, void* data )
96 {
97  ReadHDF5::HDF5ErrorHandler* h = reinterpret_cast< ReadHDF5::HDF5ErrorHandler* >( data );
98  if( h->func )
99  return ( *h->func )( stack, h->data );
100  else
101  return 0;
102 }
103 #else
104 static herr_t handle_hdf5_error( void* data )
105 {
106  ReadHDF5::HDF5ErrorHandler* h = reinterpret_cast< ReadHDF5::HDF5ErrorHandler* >( data );
107  if( h->func )
108  return ( *h->func )( h->data );
109  else
110  return 0;
111 }
112 #endif
113 
114 static void copy_sorted_file_ids( const EntityHandle* sorted_ids, long num_ids, Range& results )
115 {
116  Range::iterator hint = results.begin();
117  long i = 0;
118  while( i < num_ids )
119  {
120  EntityHandle start = sorted_ids[i];
121  for( ++i; i < num_ids && sorted_ids[i] == 1 + sorted_ids[i - 1]; ++i )
122  ;
123  hint = results.insert( hint, start, sorted_ids[i - 1] );
124  }
125 }
126 
127 static void intersect( const mhdf_EntDesc& group, const Range& range, Range& result )
128 {
130  s = Range::lower_bound( range.begin(), range.end(), group.start_id );
131  e = Range::lower_bound( s, range.end(), group.start_id + group.count );
132  result.merge( s, e );
133 }
134 
135 #define debug_barrier() debug_barrier_line( __LINE__ )
137 {
138 #ifdef MOAB_HAVE_MPI
139  if( mpiComm )
140  {
141  const unsigned threshold = 2;
142  static unsigned long count = 0;
143  if( dbgOut.get_verbosity() >= threshold )
144  {
145  dbgOut.printf( threshold, "*********** Debug Barrier %lu (@%d)***********\n", ++count, lineno );
146  MPI_Barrier( *mpiComm );
147  }
148  }
149 #else
150  if( lineno )
151  {
152  }
153 #endif
154 }
155 
157 {
158  int fileline;
161 
162  public:
164  : fileline( line ), handle( file ), enter_count( mhdf_countOpenHandles( file ) )
165  {
166  }
168  {
169  int new_count = mhdf_countOpenHandles( handle );
170  if( new_count != enter_count )
171  {
172  std::cout << "Leaked HDF5 object handle in function at " << __FILE__ << ":" << fileline << std::endl
173  << "Open at entrance: " << enter_count << std::endl
174  << "Open at exit: " << new_count << std::endl;
175  }
176  }
177 };
178 
179 #ifdef NDEBUG
180 #define CHECK_OPEN_HANDLES
181 #else
182 #define CHECK_OPEN_HANDLES CheckOpenReadHDF5Handles check_open_handles_( filePtr, __LINE__ )
183 #endif
184 
186 {
187  return new ReadHDF5( iface );
188 }
189 
191  : bufferSize( READ_HDF5_BUFFER_SIZE ), dataBuffer( NULL ), iFace( iface ), filePtr( 0 ), fileInfo( NULL ),
192  readUtil( NULL ), handleType( 0 ), indepIO( H5P_DEFAULT ), collIO( H5P_DEFAULT ), myPcomm( NULL ),
193  debugTrack( false ), dbgOut( stderr ), nativeParallel( false ), mpiComm( NULL ),
194  blockedCoordinateIO( DEFAULT_BLOCKED_COORDINATE_IO ), bcastSummary( DEFAULT_BCAST_SUMMARY ),
195  bcastDuplicateReads( DEFAULT_BCAST_DUPLICATE_READS ), setMeta( 0 ), timer( NULL ), cputime( false )
196 {
197 }
198 
200 {
201  ErrorCode rval;
202 
203  if( readUtil ) return MB_SUCCESS;
204 
205  indepIO = collIO = H5P_DEFAULT;
206  // WriteHDF5::register_known_tag_types(iFace);
207 
208  handleType = H5Tcopy( H5T_NATIVE_ULONG );
209  if( handleType < 0 ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
210 
211  if( H5Tset_size( handleType, sizeof( EntityHandle ) ) < 0 )
212  {
213  H5Tclose( handleType );
214  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
215  }
216 
217  rval = iFace->query_interface( readUtil );
218  if( MB_SUCCESS != rval )
219  {
220  H5Tclose( handleType );
221  MB_SET_ERR( rval, "ReadHDF5 Failure" );
222  }
223 
224  idMap.clear();
225  fileInfo = 0;
226  debugTrack = false;
227  myPcomm = 0;
228 
229  return MB_SUCCESS;
230 }
231 
233 {
234  if( !readUtil ) // init() failed.
235  return;
236 
237  delete[] setMeta;
238  setMeta = 0;
240  H5Tclose( handleType );
241 }
242 
243 ErrorCode ReadHDF5::set_up_read( const char* filename, const FileOptions& opts )
244 {
245  ErrorCode rval;
246  mhdf_Status status;
247  indepIO = collIO = H5P_DEFAULT;
248  mpiComm = 0;
249 
250  if( MB_SUCCESS != init() ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
251 
252 #if defined( H5Eget_auto_vers ) && H5Eget_auto_vers > 1
253  herr_t err = H5Eget_auto( H5E_DEFAULT, &errorHandler.func, &errorHandler.data );
254 #else
255  herr_t err = H5Eget_auto( &errorHandler.func, &errorHandler.data );
256 #endif
257  if( err < 0 )
258  {
259  errorHandler.func = 0;
260  errorHandler.data = 0;
261  }
262  else
263  {
264 #if defined( H5Eset_auto_vers ) && H5Eset_auto_vers > 1
265  err = H5Eset_auto( H5E_DEFAULT, &handle_hdf5_error, &errorHandler );
266 #else
267  err = H5Eset_auto( &handle_hdf5_error, &errorHandler );
268 #endif
269  if( err < 0 )
270  {
271  errorHandler.func = 0;
272  errorHandler.data = 0;
273  }
274  }
275 
276  // Set up debug output
277  int tmpval;
278  if( MB_SUCCESS == opts.get_int_option( "DEBUG_IO", 1, tmpval ) )
279  {
280  dbgOut.set_verbosity( tmpval );
281  dbgOut.set_prefix( "H5M " );
282  }
284 
285  // Enable some extra checks for reads. Note: amongst other things this
286  // will print errors if the entire file is not read, so if doing a
287  // partial read that is not a parallel read, this should be disabled.
288  debugTrack = ( MB_SUCCESS == opts.get_null_option( "DEBUG_BINIO" ) );
289 
290  opts.get_toggle_option( "BLOCKED_COORDINATE_IO", DEFAULT_BLOCKED_COORDINATE_IO, blockedCoordinateIO );
291  opts.get_toggle_option( "BCAST_SUMMARY", DEFAULT_BCAST_SUMMARY, bcastSummary );
292  opts.get_toggle_option( "BCAST_DUPLICATE_READS", DEFAULT_BCAST_DUPLICATE_READS, bcastDuplicateReads );
293 
294  // Handle parallel options
295  bool use_mpio = ( MB_SUCCESS == opts.get_null_option( "USE_MPIO" ) );
296  rval = opts.match_option( "PARALLEL", "READ_PART" );
297  bool parallel = ( rval != MB_ENTITY_NOT_FOUND );
298  nativeParallel = ( rval == MB_SUCCESS );
299  if( use_mpio && !parallel )
300  {
301  MB_SET_ERR( MB_NOT_IMPLEMENTED, "'USE_MPIO' option specified w/out 'PARALLEL' option" );
302  }
303 
304  // This option is intended for testing purposes only, and thus
305  // is not documented anywhere. Decreasing the buffer size can
306  // expose bugs that would otherwise only be seen when reading
307  // very large files.
308  rval = opts.get_int_option( "BUFFER_SIZE", bufferSize );
309  if( MB_SUCCESS != rval )
310  {
312  }
313  else if( bufferSize < (int)std::max( sizeof( EntityHandle ), sizeof( void* ) ) )
314  {
316  }
317 
318  dataBuffer = (char*)malloc( bufferSize );
320 
321  if( use_mpio || nativeParallel )
322  {
323 
324 #ifndef MOAB_HAVE_HDF5_PARALLEL
325  free( dataBuffer );
326  dataBuffer = NULL;
327  MB_SET_ERR( MB_NOT_IMPLEMENTED, "MOAB not configured with parallel HDF5 support" );
328 #else
329  MPI_Info info = MPI_INFO_NULL;
330  std::string cb_size;
331  rval = opts.get_str_option( "CB_BUFFER_SIZE", cb_size );
332  if( MB_SUCCESS == rval )
333  {
334  MPI_Info_create( &info );
335  MPI_Info_set( info, const_cast< char* >( "cb_buffer_size" ), const_cast< char* >( cb_size.c_str() ) );
336  }
337 
338  int pcomm_no = 0;
339  rval = opts.get_int_option( "PARALLEL_COMM", pcomm_no );
340  if( rval == MB_TYPE_OUT_OF_RANGE )
341  {
342  MB_SET_ERR( rval, "Invalid value for PARALLEL_COMM option" );
343  }
344  myPcomm = ParallelComm::get_pcomm( iFace, pcomm_no );
345  if( 0 == myPcomm )
346  {
347  myPcomm = new ParallelComm( iFace, MPI_COMM_WORLD );
348  }
349  const int rank = myPcomm->proc_config().proc_rank();
350  dbgOut.set_rank( rank );
352  mpiComm = new MPI_Comm( myPcomm->proc_config().proc_comm() );
353 
354 #ifndef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS
355  dbgOut.print( 1, "H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS is not defined\n" );
356 #endif
357 
358  // Open the file in serial on root to read summary
359  dbgOut.tprint( 1, "Getting file summary\n" );
360  fileInfo = 0;
361 
362  hid_t file_prop;
363  if( bcastSummary )
364  {
365  unsigned long size = 0;
366  if( rank == 0 )
367  {
368  file_prop = H5Pcreate( H5P_FILE_ACCESS );
369  err = H5Pset_fapl_mpio( file_prop, MPI_COMM_SELF, MPI_INFO_NULL );
370  assert( file_prop >= 0 );
371  assert( err >= 0 );
372  filePtr = mhdf_openFileWithOpt( filename, 0, NULL, handleType, file_prop, &status );
373  H5Pclose( file_prop );
374 
375  if( filePtr )
376  {
378  0 ); // no extra set info
379  if( !is_error( status ) )
380  {
381  size = fileInfo->total_size;
382  fileInfo->offset = (unsigned char*)fileInfo;
383  }
384  }
385  mhdf_closeFile( filePtr, &status );
386  if( fileInfo && mhdf_isError( &status ) )
387  {
388  free( fileInfo );
389  fileInfo = NULL;
390  }
391  }
392 
393  dbgOut.tprint( 1, "Communicating file summary\n" );
394  int mpi_err = MPI_Bcast( &size, 1, MPI_UNSIGNED_LONG, 0, myPcomm->proc_config().proc_comm() );
395  if( mpi_err || !size ) return MB_FAILURE;
396 
397  if( rank != 0 ) fileInfo = reinterpret_cast< mhdf_FileDesc* >( malloc( size ) );
398 
399  MPI_Bcast( fileInfo, size, MPI_BYTE, 0, myPcomm->proc_config().proc_comm() );
400 
401  if( rank != 0 ) mhdf_fixFileDesc( fileInfo, reinterpret_cast< mhdf_FileDesc* >( fileInfo->offset ) );
402  }
403 
404  file_prop = H5Pcreate( H5P_FILE_ACCESS );
405  err = H5Pset_fapl_mpio( file_prop, myPcomm->proc_config().proc_comm(), info );
406  assert( file_prop >= 0 );
407  assert( err >= 0 );
408 
409  collIO = H5Pcreate( H5P_DATASET_XFER );
410  assert( collIO > 0 );
411  err = H5Pset_dxpl_mpio( collIO, H5FD_MPIO_COLLECTIVE );
412  assert( err >= 0 );
413  indepIO = nativeParallel ? H5P_DEFAULT : collIO;
414 
415  // Re-open file in parallel
416  dbgOut.tprintf( 1, "Opening \"%s\" for parallel IO\n", filename );
417  filePtr = mhdf_openFileWithOpt( filename, 0, NULL, handleType, file_prop, &status );
418 
419  H5Pclose( file_prop );
420  if( !filePtr )
421  {
422  free( dataBuffer );
423  dataBuffer = NULL;
424  H5Pclose( indepIO );
425  if( collIO != indepIO ) H5Pclose( collIO );
426  collIO = indepIO = H5P_DEFAULT;
427  MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
428  }
429 
430  if( !bcastSummary )
431  {
433  if( is_error( status ) )
434  {
435  free( dataBuffer );
436  dataBuffer = NULL;
437  mhdf_closeFile( filePtr, &status );
438  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
439  }
440  }
441 #endif // HDF5_PARALLEL
442  }
443  else
444  {
445  // Open the file
446  filePtr = mhdf_openFile( filename, 0, NULL, handleType, &status );
447  if( !filePtr )
448  {
449  free( dataBuffer );
450  dataBuffer = NULL;
451  MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
452  }
453 
454  // Get file info
456  if( is_error( status ) )
457  {
458  free( dataBuffer );
459  dataBuffer = NULL;
460  mhdf_closeFile( filePtr, &status );
461  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
462  }
463  }
464 
466  int hslimit;
467  rval = opts.get_int_option( "HYPERSLAB_SELECT_LIMIT", hslimit );
468  if( MB_SUCCESS == rval && hslimit > 0 )
470  else
472  if( MB_SUCCESS != opts.get_null_option( "HYPERSLAB_OR" ) &&
473  ( MB_SUCCESS == opts.get_null_option( "HYPERSLAB_APPEND" ) || HDF5_can_append_hyperslabs() ) )
474  {
476  if( MB_SUCCESS != opts.get_int_option( "HYPERSLAB_SELECT_LIMIT", hslimit ) )
477  ReadHDF5Dataset::set_hyperslab_selection_limit( std::numeric_limits< int >::max() );
478  dbgOut.print( 1, "Using H5S_APPEND for hyperslab selection\n" );
479  }
480 
481  return MB_SUCCESS;
482 }
483 
485 {
486  HDF5ErrorHandler handler;
487 #if defined( H5Eget_auto_vers ) && H5Eget_auto_vers > 1
488  herr_t err = H5Eget_auto( H5E_DEFAULT, &handler.func, &handler.data );
489 #else
490  herr_t err = H5Eget_auto( &handler.func, &handler.data );
491 #endif
492  if( err >= 0 && handler.func == &handle_hdf5_error )
493  {
494  assert( handler.data == &errorHandler );
495 #if defined( H5Eget_auto_vers ) && H5Eget_auto_vers > 1
496  H5Eset_auto( H5E_DEFAULT, errorHandler.func, errorHandler.data );
497 #else
498  H5Eset_auto( errorHandler.func, errorHandler.data );
499 #endif
500  }
501 
502  free( dataBuffer );
503  dataBuffer = NULL;
504  free( fileInfo );
505  fileInfo = NULL;
506  delete mpiComm;
507  mpiComm = 0;
508 
509  if( indepIO != H5P_DEFAULT ) H5Pclose( indepIO );
510  if( collIO != indepIO ) H5Pclose( collIO );
511  collIO = indepIO = H5P_DEFAULT;
512 
513  delete[] setMeta;
514  setMeta = 0;
515 
516  mhdf_Status status;
517  mhdf_closeFile( filePtr, &status );
518  filePtr = 0;
519  return is_error( status ) ? MB_FAILURE : MB_SUCCESS;
520 }
521 
522 ErrorCode ReadHDF5::load_file( const char* filename,
523  const EntityHandle* file_set,
524  const FileOptions& opts,
525  const ReaderIface::SubsetList* subset_list,
526  const Tag* file_id_tag )
527 {
528  ErrorCode rval;
529 
530  rval = set_up_read( filename, opts );
531  if( MB_SUCCESS != rval )
532  {
533  clean_up_read( opts );
534  return rval;
535  }
536  // See if we need to report times
537 
538  rval = opts.get_null_option( "CPUTIME" );
539  if( MB_SUCCESS == rval )
540  {
541  cputime = true;
542  timer = new CpuTimer;
543  for( int i = 0; i < NUM_TIMES; i++ )
544  _times[i] = 0;
545  }
546 
547  // We read the entire set description table regardless of partial
548  // or complete reads or serial vs parallel reads
549  rval = read_all_set_meta();
550 
552  if( subset_list && MB_SUCCESS == rval )
553  rval = load_file_partial( subset_list->tag_list, subset_list->tag_list_length, subset_list->num_parts,
554  subset_list->part_number, opts );
555  else
556  rval = load_file_impl( opts );
557 
558  if( MB_SUCCESS == rval && file_id_tag )
559  {
560  dbgOut.tprint( 1, "Storing file IDs in tag\n" );
561  rval = store_file_ids( *file_id_tag );
562  }
563  ErrorCode rval3 = opts.get_null_option( "STORE_SETS_FILEIDS" );
564  if( MB_SUCCESS == rval3 )
565  {
566  rval = store_sets_file_ids();
567  if( MB_SUCCESS != rval ) return rval;
568  }
569 
571 
572  if( MB_SUCCESS == rval && 0 != file_set )
573  {
574  dbgOut.tprint( 1, "Reading QA records\n" );
575  rval = read_qa( *file_set );
576  }
577 
579  dbgOut.tprint( 1, "Cleaning up\n" );
580  ErrorCode rval2 = clean_up_read( opts );
581  if( rval == MB_SUCCESS && rval2 != MB_SUCCESS ) rval = rval2;
582 
583  if( MB_SUCCESS == rval )
584  dbgOut.tprint( 1, "Read finished.\n" );
585  else
586  {
587  std::string msg;
588  iFace->get_last_error( msg );
589  dbgOut.tprintf( 1, "READ FAILED (ERROR CODE %s): %s\n", ErrorCodeStr[rval], msg.c_str() );
590  }
591 
592  if( cputime )
593  {
595  print_times();
596  delete timer;
597  }
598  if( H5P_DEFAULT != collIO ) H5Pclose( collIO );
599  if( H5P_DEFAULT != indepIO ) H5Pclose( indepIO );
600  collIO = indepIO = H5P_DEFAULT;
601 
602  return rval;
603 }
604 
606 {
607  ErrorCode rval;
608  mhdf_Status status;
609  int i;
610 
612 
613  dbgOut.tprint( 1, "Reading all nodes...\n" );
614  Range ids;
615  if( fileInfo->nodes.count )
616  {
618  rval = read_nodes( ids );
619  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
620  }
621 
622  dbgOut.tprint( 1, "Reading all element connectivity...\n" );
623  std::vector< int > polyhedra; // Need to do these last so that faces are loaded
624  for( i = 0; i < fileInfo->num_elem_desc; ++i )
625  {
627  {
628  polyhedra.push_back( i );
629  continue;
630  }
631 
632  rval = read_elems( i );
633  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
634  }
635  for( std::vector< int >::iterator it = polyhedra.begin(); it != polyhedra.end(); ++it )
636  {
637  rval = read_elems( *it );
638  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
639  }
640 
641  dbgOut.tprint( 1, "Reading all sets...\n" );
642  ids.clear();
643  if( fileInfo->sets.count )
644  {
646  rval = read_sets( ids );
647  if( rval != MB_SUCCESS )
648  {
649  MB_SET_ERR( rval, "ReadHDF5 Failure" );
650  }
651  }
652 
653  dbgOut.tprint( 1, "Reading all adjacencies...\n" );
654  for( i = 0; i < fileInfo->num_elem_desc; ++i )
655  {
656  if( !fileInfo->elems[i].have_adj ) continue;
657 
658  long table_len;
659  hid_t table = mhdf_openAdjacency( filePtr, fileInfo->elems[i].handle, &table_len, &status );
660  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
661 
662  rval = read_adjacencies( table, table_len );
663  mhdf_closeData( filePtr, table, &status );
664  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
665  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
666  }
667 
668  dbgOut.tprint( 1, "Reading all tags...\n" );
669  for( i = 0; i < fileInfo->num_tag_desc; ++i )
670  {
671  rval = read_tag( i );
672  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
673  }
674 
675  dbgOut.tprint( 1, "Core read finished. Cleaning up...\n" );
676  return MB_SUCCESS;
677 }
678 
679 ErrorCode ReadHDF5::find_int_tag( const char* name, int& index )
680 {
681  for( index = 0; index < fileInfo->num_tag_desc; ++index )
682  if( !strcmp( name, fileInfo->tags[index].name ) ) break;
683 
684  if( index == fileInfo->num_tag_desc )
685  {
686  MB_SET_ERR( MB_TAG_NOT_FOUND, "File does not contain subset tag '" << name << "'" );
687  }
688 
689  if( fileInfo->tags[index].type != mhdf_INTEGER || fileInfo->tags[index].size != 1 )
690  {
691  MB_SET_ERR( MB_TAG_NOT_FOUND, "Tag ' " << name << "' does not contain single integer value" );
692  }
693 
694  return MB_SUCCESS;
695 }
696 
697 ErrorCode ReadHDF5::get_subset_ids( const ReaderIface::IDTag* subset_list, int subset_list_length, Range& file_ids )
698 {
699  ErrorCode rval;
700 
701  for( int i = 0; i < subset_list_length; ++i )
702  {
703  int tag_index;
704  rval = find_int_tag( subset_list[i].tag_name, tag_index );
705  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
706 
707  Range tmp_file_ids;
708  if( !subset_list[i].num_tag_values )
709  {
710  rval = get_tagged_entities( tag_index, tmp_file_ids );
711  }
712  else
713  {
714  std::vector< int > ids( subset_list[i].tag_values,
715  subset_list[i].tag_values + subset_list[i].num_tag_values );
716  std::sort( ids.begin(), ids.end() );
717  rval = search_tag_values( tag_index, ids, tmp_file_ids );
718  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
719  }
720 
721  if( tmp_file_ids.empty() ) MB_CHK_ERR( MB_ENTITY_NOT_FOUND );
722 
723  if( i == 0 )
724  file_ids.swap( tmp_file_ids );
725  else
726  file_ids = intersect( tmp_file_ids, file_ids );
727  }
728 
729  return MB_SUCCESS;
730 }
731 
732 ErrorCode ReadHDF5::get_partition( Range& tmp_file_ids, int num_parts, int part_number )
733 {
735 
736  // Check that the tag only identified sets
737  if( (unsigned long)fileInfo->sets.start_id > tmp_file_ids.front() )
738  {
739  dbgOut.print( 2, "Ignoring non-set entities with partition set tag\n" );
740  tmp_file_ids.erase( tmp_file_ids.begin(), tmp_file_ids.lower_bound( (EntityHandle)fileInfo->sets.start_id ) );
741  }
742  unsigned long set_end = (unsigned long)fileInfo->sets.start_id + fileInfo->sets.count;
743  if( tmp_file_ids.back() >= set_end )
744  {
745  dbgOut.print( 2, "Ignoring non-set entities with partition set tag\n" );
746  tmp_file_ids.erase( tmp_file_ids.upper_bound( (EntityHandle)set_end ), tmp_file_ids.end() );
747  }
748 
749  Range::iterator s = tmp_file_ids.begin();
750  size_t num_per_proc = tmp_file_ids.size() / num_parts;
751  size_t num_extra = tmp_file_ids.size() % num_parts;
752  Range::iterator e;
753  if( part_number < (long)num_extra )
754  {
755  s += ( num_per_proc + 1 ) * part_number;
756  e = s;
757  e += ( num_per_proc + 1 );
758  }
759  else
760  {
761  s += num_per_proc * part_number + num_extra;
762  e = s;
763  e += num_per_proc;
764  }
765  tmp_file_ids.erase( e, tmp_file_ids.end() );
766  tmp_file_ids.erase( tmp_file_ids.begin(), s );
767 
768  return MB_SUCCESS;
769 }
770 
772  int subset_list_length,
773  int num_parts,
774  int part_number,
775  const FileOptions& opts )
776 {
777  mhdf_Status status;
778 
779  static MPEState mpe_event( "ReadHDF5", "yellow" );
780 
781  mpe_event.start( "gather parts" );
782 
784 
785  for( int i = 0; i < subset_list_length; ++i )
786  {
787  dbgOut.printf( 2, "Select by \"%s\" with num_tag_values = %d\n", subset_list[i].tag_name,
788  subset_list[i].num_tag_values );
789  if( subset_list[i].num_tag_values )
790  {
791  assert( 0 != subset_list[i].tag_values );
792  dbgOut.printf( 2, " \"%s\" values = { %d", subset_list[i].tag_name, subset_list[i].tag_values[0] );
793  for( int j = 1; j < subset_list[i].num_tag_values; ++j )
794  dbgOut.printf( 2, ", %d", subset_list[i].tag_values[j] );
795  dbgOut.printf( 2, " }\n" );
796  }
797  }
798  if( num_parts ) dbgOut.printf( 2, "Partition with num_parts = %d and part_number = %d\n", num_parts, part_number );
799 
800  dbgOut.tprint( 1, "RETRIEVING TAGGED ENTITIES\n" );
801 
802  Range file_ids;
803  ErrorCode rval = get_subset_ids( subset_list, subset_list_length, file_ids );
804  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
805 
807 
808  if( num_parts )
809  {
810  /*if (num_parts>(int)file_ids.size())
811  {
812  MB_SET_ERR(MB_FAILURE, "Only " << file_ids.size() << " parts to distribute to " <<
813  num_parts << " processes.");
814  }*/
815  rval = get_partition( file_ids, num_parts, part_number );
816  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
817  }
818 
820 
821  dbgOut.print_ints( 4, "Set file IDs for partial read: ", file_ids );
822  mpe_event.end();
823  mpe_event.start( "gather related sets" );
824  dbgOut.tprint( 1, "GATHERING ADDITIONAL ENTITIES\n" );
825 
826  enum RecusiveSetMode
827  {
828  RSM_NONE,
829  RSM_SETS,
830  RSM_CONTENTS
831  };
832  const char* const set_opts[] = { "NONE", "SETS", "CONTENTS", NULL };
833  int child_mode;
834  rval = opts.match_option( "CHILDREN", set_opts, child_mode );
835  if( MB_ENTITY_NOT_FOUND == rval )
836  child_mode = RSM_CONTENTS;
837  else if( MB_SUCCESS != rval )
838  {
839  MB_SET_ERR( rval, "Invalid value for 'CHILDREN' option" );
840  }
841  int content_mode;
842  rval = opts.match_option( "SETS", set_opts, content_mode );
843  if( MB_ENTITY_NOT_FOUND == rval )
844  content_mode = RSM_CONTENTS;
845  else if( MB_SUCCESS != rval )
846  {
847  MB_SET_ERR( rval, "Invalid value for 'SETS' option" );
848  }
849 
850  // If we want the contents of contained/child sets,
851  // search for them now (before gathering the non-set contents
852  // of the sets.)
853  Range sets;
854  intersect( fileInfo->sets, file_ids, sets );
855  if( content_mode == RSM_CONTENTS || child_mode == RSM_CONTENTS )
856  {
857  dbgOut.tprint( 1, " doing read_set_ids_recursive\n" );
858  rval = read_set_ids_recursive( sets, content_mode == RSM_CONTENTS, child_mode == RSM_CONTENTS );
859  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
860  }
861 
863  debug_barrier();
864 
865  // Get elements and vertices contained in sets
866  dbgOut.tprint( 1, " doing get_set_contents\n" );
867  rval = get_set_contents( sets, file_ids );
868  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
869 
871 
872  dbgOut.print_ints( 5, "File IDs for partial read: ", file_ids );
873  debug_barrier();
874  mpe_event.end();
875  dbgOut.tprint( 1, "GATHERING NODE IDS\n" );
876 
877  // Figure out the maximum dimension of entity to be read
878  int max_dim = 0;
879  for( int i = 0; i < fileInfo->num_elem_desc; ++i )
880  {
881  EntityType type = CN::EntityTypeFromName( fileInfo->elems[i].type );
882  if( type <= MBVERTEX || type >= MBENTITYSET )
883  {
884  assert( false ); // For debug code die for unknown element types
885  continue; // For release code, skip unknown element types
886  }
887  int dim = CN::Dimension( type );
888  if( dim > max_dim )
889  {
890  Range subset;
891  intersect( fileInfo->elems[i].desc, file_ids, subset );
892  if( !subset.empty() ) max_dim = dim;
893  }
894  }
895 #ifdef MOAB_HAVE_MPI
896  if( nativeParallel )
897  {
898  int send = max_dim;
899  MPI_Allreduce( &send, &max_dim, 1, MPI_INT, MPI_MAX, *mpiComm );
900  }
901 #endif
902 
903  // If input contained any polyhedra, then need to get faces
904  // of the polyhedra before the next loop because we need to
905  // read said faces in that loop.
906  for( int i = 0; i < fileInfo->num_elem_desc; ++i )
907  {
908  EntityType type = CN::EntityTypeFromName( fileInfo->elems[i].type );
909  if( type != MBPOLYHEDRON ) continue;
910 
911  debug_barrier();
912  dbgOut.print( 2, " Getting polyhedra faces\n" );
913  mpe_event.start( "reading connectivity for ", fileInfo->elems[i].handle );
914 
915  Range polyhedra;
916  intersect( fileInfo->elems[i].desc, file_ids, polyhedra );
917  rval = read_elems( i, polyhedra, &file_ids );
918  mpe_event.end( rval );
919  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
920  }
921 
923  // Get node file ids for all elements
924  Range nodes;
925  intersect( fileInfo->nodes, file_ids, nodes );
926  for( int i = 0; i < fileInfo->num_elem_desc; ++i )
927  {
928  EntityType type = CN::EntityTypeFromName( fileInfo->elems[i].type );
929  if( type <= MBVERTEX || type >= MBENTITYSET )
930  {
931  assert( false ); // For debug code die for unknown element types
932  continue; // For release code, skip unknown element types
933  }
934  if( MBPOLYHEDRON == type ) continue;
935 
936  debug_barrier();
937  dbgOut.printf( 2, " Getting element node IDs for: %s\n", fileInfo->elems[i].handle );
938 
939  Range subset;
940  intersect( fileInfo->elems[i].desc, file_ids, subset );
941  mpe_event.start( "reading connectivity for ", fileInfo->elems[i].handle );
942 
943  // If dimension is max_dim, then we can create the elements now
944  // so we don't have to read the table again later (connectivity
945  // will be fixed up after nodes are created when update_connectivity())
946  // is called. For elements of a smaller dimension, we just build
947  // the node ID range now because a) we'll have to read the whole
948  // connectivity table again later, and b) we don't want to worry
949  // about accidentally creating multiple copies of the same element.
950  if( CN::Dimension( type ) == max_dim )
951  rval = read_elems( i, subset, &nodes );
952  else
953  rval = read_elems( i, subset, nodes );
954  mpe_event.end( rval );
955  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
956  }
958  debug_barrier();
959  mpe_event.start( "read coords" );
960  dbgOut.tprintf( 1, "READING NODE COORDINATES (%lu nodes in %lu selects)\n", (unsigned long)nodes.size(),
961  (unsigned long)nodes.psize() );
962 
963  // Read node coordinates and create vertices in MOAB
964  // NOTE: This populates the RangeMap with node file ids,
965  // which is expected by read_node_adj_elems.
966  rval = read_nodes( nodes );
967  mpe_event.end( rval );
968  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
969 
971 
972  debug_barrier();
973  dbgOut.tprint( 1, "READING ELEMENTS\n" );
974 
975  // Decide if we need to read additional elements
976  enum SideMode
977  {
978  SM_EXPLICIT,
979  SM_NODES,
980  SM_SIDES
981  };
982  int side_mode;
983  const char* const options[] = { "EXPLICIT", "NODES", "SIDES", 0 };
984  rval = opts.match_option( "ELEMENTS", options, side_mode );
985  if( MB_ENTITY_NOT_FOUND == rval )
986  {
987  // If only nodes were specified, then default to "NODES", otherwise
988  // default to "SIDES".
989  if( 0 == max_dim )
990  side_mode = SM_NODES;
991  else
992  side_mode = SM_SIDES;
993  }
994  else if( MB_SUCCESS != rval )
995  {
996  MB_SET_ERR( rval, "Invalid value for 'ELEMENTS' option" );
997  }
998 
999  if( side_mode == SM_SIDES /*ELEMENTS=SIDES*/ && max_dim == 0 /*node-based*/ )
1000  {
1001  // Read elements until we find something. Once we find something,
1002  // read only elements of the same dimension. NOTE: loop termination
1003  // criterion changes on both sides (max_dim can be changed in loop
1004  // body).
1005  for( int dim = 3; dim >= max_dim; --dim )
1006  {
1007  for( int i = 0; i < fileInfo->num_elem_desc; ++i )
1008  {
1009  EntityType type = CN::EntityTypeFromName( fileInfo->elems[i].type );
1010  if( CN::Dimension( type ) == dim )
1011  {
1012  debug_barrier();
1013  dbgOut.tprintf( 2, " Reading node-adjacent elements for: %s\n", fileInfo->elems[i].handle );
1014  mpe_event.start( "reading connectivity for ", fileInfo->elems[i].handle );
1015  Range ents;
1016  rval = read_node_adj_elems( fileInfo->elems[i] );
1017  mpe_event.end( rval );
1018  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1019  if( !ents.empty() ) max_dim = 3;
1020  }
1021  }
1022  }
1023  }
1024 
1026  Range side_entities;
1027  if( side_mode != SM_EXPLICIT /*ELEMENTS=NODES || ELEMENTS=SIDES*/ )
1028  {
1029  if( 0 == max_dim ) max_dim = 4;
1030  // Now read any additional elements for which we've already read all
1031  // of the nodes.
1032  for( int dim = max_dim - 1; dim > 0; --dim )
1033  {
1034  for( int i = 0; i < fileInfo->num_elem_desc; ++i )
1035  {
1036  EntityType type = CN::EntityTypeFromName( fileInfo->elems[i].type );
1037  if( CN::Dimension( type ) == dim )
1038  {
1039  debug_barrier();
1040  dbgOut.tprintf( 2, " Reading node-adjacent elements for: %s\n", fileInfo->elems[i].handle );
1041  mpe_event.start( "reading connectivity for ", fileInfo->elems[i].handle );
1042  rval = read_node_adj_elems( fileInfo->elems[i], &side_entities );
1043  mpe_event.end( rval );
1044  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1045  }
1046  }
1047  }
1048  }
1049 
1050  // We need to do this here for polyhedra to be handled correctly.
1051  // We have to wait until the faces are read in the above code block,
1052  // but need to create the connectivity before doing update_connectivity,
1053  // which might otherwise delete polyhedra faces.
1055 
1056  debug_barrier();
1057  dbgOut.tprint( 1, "UPDATING CONNECTIVITY ARRAYS FOR READ ELEMENTS\n" );
1058  mpe_event.start( "updating connectivity for elements read before vertices" );
1059  rval = update_connectivity();
1060  mpe_event.end();
1061  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1062 
1064 
1065  dbgOut.tprint( 1, "READING ADJACENCIES\n" );
1066  for( int i = 0; i < fileInfo->num_elem_desc; ++i )
1067  {
1068  if (fileInfo->elems[i].have_adj /*&&
1069  idMap.intersects(fileInfo->elems[i].desc.start_id, fileInfo->elems[i].desc.count) */)
1070  {
1071  mpe_event.start( "reading adjacencies for ", fileInfo->elems[i].handle );
1072  long len;
1073  hid_t th = mhdf_openAdjacency( filePtr, fileInfo->elems[i].handle, &len, &status );
1074  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1075 
1076  rval = read_adjacencies( th, len );
1077  mhdf_closeData( filePtr, th, &status );
1078  mpe_event.end( rval );
1079  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1080  }
1081  }
1082 
1084 
1085  // If doing ELEMENTS=SIDES then we need to delete any entities
1086  // that we read that aren't actually sides (e.g. an interior face
1087  // that connects two disjoint portions of the part). Both
1088  // update_connectivity and reading of any explicit adjacencies must
1089  // happen before this.
1090  if( side_mode == SM_SIDES )
1091  {
1092  debug_barrier();
1093  mpe_event.start( "cleaning up non-side lower-dim elements" );
1094  dbgOut.tprint( 1, "CHECKING FOR AND DELETING NON-SIDE ELEMENTS\n" );
1095  rval = delete_non_side_elements( side_entities );
1096  mpe_event.end( rval );
1097  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1098  }
1099 
1101 
1102  debug_barrier();
1103  dbgOut.tprint( 1, "READING SETS\n" );
1104 
1105  // If reading contained/child sets but not their contents then find
1106  // them now. If we were also reading their contents we would
1107  // have found them already.
1108  if( content_mode == RSM_SETS || child_mode == RSM_SETS )
1109  {
1110  dbgOut.tprint( 1, " doing read_set_ids_recursive\n" );
1111  mpe_event.start( "finding recursively contained sets" );
1112  rval = read_set_ids_recursive( sets, content_mode == RSM_SETS, child_mode == RSM_SETS );
1113  mpe_event.end( rval );
1114  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1115  }
1116 
1118 
1119  dbgOut.tprint( 1, " doing find_sets_containing\n" );
1120  mpe_event.start( "finding sets containing any read entities" );
1121 
1122  // Decide whether to read set-containing parents
1123  bool read_set_containing_parents = true;
1124  std::string tmp_opt;
1125  rval = opts.get_option( "NO_SET_CONTAINING_PARENTS", tmp_opt );
1126  if( MB_SUCCESS == rval ) read_set_containing_parents = false;
1127 
1128  // Append file IDs of sets containing any of the nodes or elements
1129  // we've read up to this point.
1130  rval = find_sets_containing( sets, read_set_containing_parents );
1131  mpe_event.end( rval );
1132  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1133 
1135 
1136  // Now actually read all set data and instantiate sets in MOAB.
1137  // Get any contained sets out of file_ids.
1138  mpe_event.start( "reading set contents/parents/children" );
1139  EntityHandle first_set = fileInfo->sets.start_id;
1140  sets.merge( file_ids.lower_bound( first_set ), file_ids.lower_bound( first_set + fileInfo->sets.count ) );
1141  dbgOut.tprint( 1, " doing read_sets\n" );
1142  rval = read_sets( sets );
1143  mpe_event.end( rval );
1144  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1145 
1147 
1148  dbgOut.tprint( 1, "READING TAGS\n" );
1149 
1150  for( int i = 0; i < fileInfo->num_tag_desc; ++i )
1151  {
1152  mpe_event.start( "reading tag: ", fileInfo->tags[i].name );
1153  rval = read_tag( i );
1154  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1155  }
1156 
1158 
1159  dbgOut.tprint( 1, "PARTIAL READ COMPLETE.\n" );
1160 
1161  return MB_SUCCESS;
1162 }
1163 
1165  const std::vector< int >& sorted_values,
1166  Range& file_ids,
1167  bool sets_only )
1168 {
1169  ErrorCode rval;
1170  mhdf_Status status;
1171  std::vector< EntityHandle >::iterator iter;
1172  const mhdf_TagDesc& tag = fileInfo->tags[tag_index];
1173  long size;
1174  long start_id;
1175 
1177 
1178  debug_barrier();
1179 
1180  // Do dense data
1181 
1182  hid_t table;
1183  const char* name;
1184  std::vector< EntityHandle > indices;
1185  // These are probably in order of dimension, so iterate
1186  // in reverse order to make Range insertions more efficient.
1187  std::vector< int > grp_indices( tag.dense_elem_indices, tag.dense_elem_indices + tag.num_dense_indices );
1188  for( std::vector< int >::reverse_iterator i = grp_indices.rbegin(); i != grp_indices.rend(); ++i )
1189  {
1190  int idx = *i;
1191  if( idx == -2 )
1192  {
1193  name = mhdf_set_type_handle();
1194  start_id = fileInfo->sets.start_id;
1195  }
1196  else if( sets_only )
1197  {
1198  continue;
1199  }
1200  else if( idx == -1 )
1201  {
1202  name = mhdf_node_type_handle();
1203  start_id = fileInfo->nodes.start_id;
1204  }
1205  else
1206  {
1207  if( idx < 0 || idx >= fileInfo->num_elem_desc ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1208  name = fileInfo->elems[idx].handle;
1209  start_id = fileInfo->elems[idx].desc.start_id;
1210  }
1211  table = mhdf_openDenseTagData( filePtr, tag.name, name, &size, &status );
1212  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1213  rval = search_tag_values( table, size, sorted_values, indices );
1214  mhdf_closeData( filePtr, table, &status );
1215  if( MB_SUCCESS != rval || is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1216  // Convert from table indices to file IDs and add to result list
1217  std::sort( indices.begin(), indices.end(), std::greater< EntityHandle >() );
1218  std::transform( indices.begin(), indices.end(), range_inserter( file_ids ),
1219  // std::bind1st(std::plus<long>(), start_id));
1220  std::bind( std::plus< long >(), start_id, std::placeholders::_1 ) );
1221  indices.clear();
1222  }
1223 
1224  if( !tag.have_sparse ) return MB_SUCCESS;
1225 
1226  // Do sparse data
1227 
1228  hid_t tables[2];
1229  long junk; // Redundant value for non-variable-length tags
1230  mhdf_openSparseTagData( filePtr, tag.name, &size, &junk, tables, &status );
1231  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1232  rval = search_tag_values( tables[1], size, sorted_values, indices );
1233  mhdf_closeData( filePtr, tables[1], &status );
1234  if( MB_SUCCESS != rval || is_error( status ) )
1235  {
1236  mhdf_closeData( filePtr, tables[0], &status );
1237  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1238  }
1239  // Convert to ranges
1240  std::sort( indices.begin(), indices.end() );
1241  std::vector< EntityHandle > ranges;
1242  iter = indices.begin();
1243  while( iter != indices.end() )
1244  {
1245  ranges.push_back( *iter );
1246  EntityHandle last = *iter;
1247  for( ++iter; iter != indices.end() && ( last + 1 ) == *iter; ++iter, ++last )
1248  ;
1249  ranges.push_back( last );
1250  }
1251  // Read file ids
1252  iter = ranges.begin();
1253  unsigned long offset = 0;
1254  while( iter != ranges.end() )
1255  {
1256  long begin = *iter;
1257  ++iter;
1258  long end = *iter;
1259  ++iter;
1260  mhdf_readSparseTagEntitiesWithOpt( tables[0], begin, end - begin + 1, handleType, &indices[offset], indepIO,
1261  &status );
1262  if( is_error( status ) )
1263  {
1264  mhdf_closeData( filePtr, tables[0], &status );
1265  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1266  }
1267  offset += end - begin + 1;
1268  }
1269  mhdf_closeData( filePtr, tables[0], &status );
1270  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1271  assert( offset == indices.size() );
1272  std::sort( indices.begin(), indices.end() );
1273 
1274  if( sets_only )
1275  {
1276  iter = std::lower_bound( indices.begin(), indices.end(),
1278  indices.erase( iter, indices.end() );
1279  iter = std::lower_bound( indices.begin(), indices.end(), fileInfo->sets.start_id );
1280  indices.erase( indices.begin(), iter );
1281  }
1282  copy_sorted_file_ids( &indices[0], indices.size(), file_ids );
1283 
1284  return MB_SUCCESS;
1285 }
1286 
1287 ErrorCode ReadHDF5::get_tagged_entities( int tag_index, Range& file_ids )
1288 {
1289  const mhdf_TagDesc& tag = fileInfo->tags[tag_index];
1290 
1292 
1293  // Do dense data
1294  Range::iterator hint = file_ids.begin();
1295  for( int i = 0; i < tag.num_dense_indices; ++i )
1296  {
1297  int idx = tag.dense_elem_indices[i];
1298  mhdf_EntDesc* ents;
1299  if( idx == -2 )
1300  ents = &fileInfo->sets;
1301  else if( idx == -1 )
1302  ents = &fileInfo->nodes;
1303  else
1304  {
1305  if( idx < 0 || idx >= fileInfo->num_elem_desc ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1306  ents = &( fileInfo->elems[idx].desc );
1307  }
1308 
1309  EntityHandle h = (EntityHandle)ents->start_id;
1310  hint = file_ids.insert( hint, h, h + ents->count - 1 );
1311  }
1312 
1313  if( !tag.have_sparse ) return MB_SUCCESS;
1314 
1315  // Do sparse data
1316 
1317  mhdf_Status status;
1318  hid_t tables[2];
1319  long size, junk;
1320  mhdf_openSparseTagData( filePtr, tag.name, &size, &junk, tables, &status );
1321  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1322  mhdf_closeData( filePtr, tables[1], &status );
1323  if( is_error( status ) )
1324  {
1325  mhdf_closeData( filePtr, tables[0], &status );
1326  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1327  }
1328 
1329  hid_t file_type = H5Dget_type( tables[0] );
1330  if( file_type < 0 ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1331 
1332  hint = file_ids.begin();
1333  EntityHandle* buffer = reinterpret_cast< EntityHandle* >( dataBuffer );
1334  const long buffer_size = bufferSize / std::max( sizeof( EntityHandle ), H5Tget_size( file_type ) );
1335  long remaining = size, offset = 0;
1336  while( remaining )
1337  {
1338  long count = std::min( buffer_size, remaining );
1339  assert_range( buffer, count );
1340  mhdf_readSparseTagEntitiesWithOpt( *tables, offset, count, file_type, buffer, collIO, &status );
1341  if( is_error( status ) )
1342  {
1343  H5Tclose( file_type );
1344  mhdf_closeData( filePtr, *tables, &status );
1345  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1346  }
1347  H5Tconvert( file_type, handleType, count, buffer, NULL, H5P_DEFAULT );
1348 
1349  std::sort( buffer, buffer + count );
1350  for( long i = 0; i < count; ++i )
1351  hint = file_ids.insert( hint, buffer[i], buffer[i] );
1352 
1353  remaining -= count;
1354  offset += count;
1355  }
1356 
1357  H5Tclose( file_type );
1358  mhdf_closeData( filePtr, *tables, &status );
1359  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1360 
1361  return MB_SUCCESS;
1362 }
1363 
1365  unsigned long table_size,
1366  const std::vector< int >& sorted_values,
1367  std::vector< EntityHandle >& value_indices )
1368 {
1369  debug_barrier();
1370 
1372 
1373  mhdf_Status status;
1374  size_t chunk_size = bufferSize / sizeof( int );
1375  int* buffer = reinterpret_cast< int* >( dataBuffer );
1376  size_t remaining = table_size, offset = 0;
1377  while( remaining )
1378  {
1379  // Get a block of tag values
1380  size_t count = std::min( chunk_size, remaining );
1381  assert_range( buffer, count );
1382  mhdf_readTagValuesWithOpt( tag_table, offset, count, H5T_NATIVE_INT, buffer, collIO, &status );
1383  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1384 
1385  // Search tag values
1386  for( size_t i = 0; i < count; ++i )
1387  if( std::binary_search( sorted_values.begin(), sorted_values.end(), (int)buffer[i] ) )
1388  value_indices.push_back( i + offset );
1389 
1390  offset += count;
1391  remaining -= count;
1392  }
1393 
1394  return MB_SUCCESS;
1395 }
1396 
1397 ErrorCode ReadHDF5::read_nodes( const Range& node_file_ids )
1398 {
1399  ErrorCode rval;
1400  mhdf_Status status;
1401  const int dim = fileInfo->nodes.vals_per_ent;
1402  Range range;
1403 
1405 
1406  if( node_file_ids.empty() && !nativeParallel ) return MB_SUCCESS;
1407 
1408  int cdim;
1409  rval = iFace->get_dimension( cdim );
1410  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1411 
1412  if( cdim < dim )
1413  {
1414  rval = iFace->set_dimension( dim );
1415  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1416  }
1417 
1418  hid_t data_id = mhdf_openNodeCoordsSimple( filePtr, &status );
1419  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1420 
1421  EntityHandle handle;
1422  std::vector< double* > arrays( dim );
1423  const size_t num_nodes = node_file_ids.size();
1424  if( num_nodes > 0 )
1425  {
1426  rval = readUtil->get_node_coords( dim, (int)num_nodes, 0, handle, arrays );
1427  if( MB_SUCCESS != rval )
1428  {
1429  mhdf_closeData( filePtr, data_id, &status );
1430  MB_SET_ERR( rval, "ReadHDF5 Failure" );
1431  }
1432  }
1433 
1434  if( blockedCoordinateIO )
1435  {
1436  try
1437  {
1438  for( int d = 0; d < dim; ++d )
1439  {
1440  ReadHDF5Dataset reader( "blocked coords", data_id, nativeParallel, mpiComm, false );
1441  reader.set_column( d );
1442  reader.set_file_ids( node_file_ids, fileInfo->nodes.start_id, num_nodes, H5T_NATIVE_DOUBLE );
1443  dbgOut.printf( 3, "Reading %lu chunks for coordinate dimension %d\n", reader.get_read_count(), d );
1444  // Should normally only have one read call, unless sparse nature
1445  // of file_ids caused reader to do something strange
1446  size_t count, offset = 0;
1447  int nn = 0;
1448  while( !reader.done() )
1449  {
1450  dbgOut.printf( 3, "Reading chunk %d for dimension %d\n", ++nn, d );
1451  reader.read( arrays[d] + offset, count );
1452  offset += count;
1453  }
1454  if( offset != num_nodes )
1455  {
1456  mhdf_closeData( filePtr, data_id, &status );
1457  assert( false );
1458  return MB_FAILURE;
1459  }
1460  }
1461  }
1463  {
1464  mhdf_closeData( filePtr, data_id, &status );
1465  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1466  }
1467  }
1468  else
1469  { // !blockedCoordinateIO
1470  double* buffer = (double*)dataBuffer;
1471  long chunk_size = bufferSize / ( 3 * sizeof( double ) );
1472  long coffset = 0;
1473  int nn = 0;
1474  try
1475  {
1476  ReadHDF5Dataset reader( "interleaved coords", data_id, nativeParallel, mpiComm, false );
1477  reader.set_file_ids( node_file_ids, fileInfo->nodes.start_id, chunk_size, H5T_NATIVE_DOUBLE );
1478  dbgOut.printf( 3, "Reading %lu chunks for coordinate coordinates\n", reader.get_read_count() );
1479  while( !reader.done() )
1480  {
1481  dbgOut.tprintf( 3, "Reading chunk %d of node coords\n", ++nn );
1482 
1483  size_t count;
1484  reader.read( buffer, count );
1485 
1486  for( size_t i = 0; i < count; ++i )
1487  for( int d = 0; d < dim; ++d )
1488  arrays[d][coffset + i] = buffer[dim * i + d];
1489  coffset += count;
1490  }
1491  }
1493  {
1494  mhdf_closeData( filePtr, data_id, &status );
1495  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1496  }
1497  }
1498 
1499  dbgOut.print( 3, "Closing node coordinate table\n" );
1500  mhdf_closeData( filePtr, data_id, &status );
1501  for( int d = dim; d < cdim; ++d )
1502  memset( arrays[d], 0, num_nodes * sizeof( double ) );
1503 
1504  dbgOut.printf( 3, "Updating ID to handle map for %lu nodes\n", (unsigned long)node_file_ids.size() );
1505  return insert_in_id_map( node_file_ids, handle );
1506 }
1507 
1509 {
1510  Range ids;
1511  ids.insert( fileInfo->elems[i].desc.start_id,
1512  fileInfo->elems[i].desc.start_id + fileInfo->elems[i].desc.count - 1 );
1513  return read_elems( i, ids );
1514 }
1515 
1516 ErrorCode ReadHDF5::read_elems( int i, const Range& file_ids, Range* node_ids )
1517 {
1518  if( fileInfo->elems[i].desc.vals_per_ent < 0 )
1519  {
1520  if( node_ids != 0 ) // Not implemented for version 3 format of poly data
1522  return read_poly( fileInfo->elems[i], file_ids );
1523  }
1524  else
1525  return read_elems( fileInfo->elems[i], file_ids, node_ids );
1526 }
1527 
1528 ErrorCode ReadHDF5::read_elems( const mhdf_ElemDesc& elems, const Range& file_ids, Range* node_ids )
1529 {
1531 
1532  debug_barrier();
1533  dbgOut.tprintf( 1, "READING %s CONNECTIVITY (%lu elems in %lu selects)\n", elems.handle,
1534  (unsigned long)file_ids.size(), (unsigned long)file_ids.psize() );
1535 
1536  ErrorCode rval = MB_SUCCESS;
1537  mhdf_Status status;
1538 
1539  EntityType type = CN::EntityTypeFromName( elems.type );
1540  if( type == MBMAXTYPE )
1541  {
1542  MB_SET_ERR( MB_FAILURE, "Unknown element type: \"" << elems.type << "\"" );
1543  }
1544 
1545  const int nodes_per_elem = elems.desc.vals_per_ent;
1546  const size_t count = file_ids.size();
1547  hid_t data_id = mhdf_openConnectivitySimple( filePtr, elems.handle, &status );
1548  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1549 
1550  EntityHandle handle;
1551  EntityHandle* array = 0;
1552  if( count > 0 ) rval = readUtil->get_element_connect( count, nodes_per_elem, type, 0, handle, array );
1553  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1554 
1555  try
1556  {
1557  EntityHandle* buffer = reinterpret_cast< EntityHandle* >( dataBuffer );
1558  const size_t buffer_size = bufferSize / ( sizeof( EntityHandle ) * nodes_per_elem );
1559  ReadHDF5Dataset reader( elems.handle, data_id, nativeParallel, mpiComm );
1560  reader.set_file_ids( file_ids, elems.desc.start_id, buffer_size, handleType );
1561  dbgOut.printf( 3, "Reading connectivity in %lu chunks for element group \"%s\"\n", reader.get_read_count(),
1562  elems.handle );
1563  EntityHandle* iter = array;
1564  int nn = 0;
1565  while( !reader.done() )
1566  {
1567  dbgOut.printf( 3, "Reading chunk %d for \"%s\"\n", ++nn, elems.handle );
1568 
1569  size_t num_read;
1570  reader.read( buffer, num_read );
1571  iter = std::copy( buffer, buffer + num_read * nodes_per_elem, iter );
1572 
1573  if( node_ids )
1574  {
1575  std::sort( buffer, buffer + num_read * nodes_per_elem );
1576  num_read = std::unique( buffer, buffer + num_read * nodes_per_elem ) - buffer;
1577  copy_sorted_file_ids( buffer, num_read, *node_ids );
1578  }
1579  }
1580  assert( iter - array == (ptrdiff_t)count * nodes_per_elem );
1581  }
1583  {
1584  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1585  }
1586 
1587  if( !node_ids )
1588  {
1589  rval = convert_id_to_handle( array, count * nodes_per_elem );
1590  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1591 
1592  rval = readUtil->update_adjacencies( handle, count, nodes_per_elem, array );
1593  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1594  }
1595  else
1596  {
1597  IDConnectivity t;
1598  t.handle = handle;
1599  t.count = count;
1600  t.nodes_per_elem = nodes_per_elem;
1601  t.array = array;
1602  idConnectivityList.push_back( t );
1603  }
1604 
1605  return insert_in_id_map( file_ids, handle );
1606 }
1607 
1609 {
1610  ErrorCode rval;
1611  std::vector< IDConnectivity >::iterator i;
1612  for( i = idConnectivityList.begin(); i != idConnectivityList.end(); ++i )
1613  {
1614  rval = convert_id_to_handle( i->array, i->count * i->nodes_per_elem );
1615  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1616 
1617  rval = readUtil->update_adjacencies( i->handle, i->count, i->nodes_per_elem, i->array );
1618  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1619  }
1620  idConnectivityList.clear();
1621 
1622  return MB_SUCCESS;
1623 }
1624 
1626 {
1627  mhdf_Status status;
1628  ErrorCode rval;
1629 
1631 
1632  hid_t table = mhdf_openConnectivitySimple( filePtr, group.handle, &status );
1633  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1634 
1635  rval = read_node_adj_elems( group, table, handles_out );
1636 
1637  mhdf_closeData( filePtr, table, &status );
1638  if( MB_SUCCESS == rval && is_error( status ) ) MB_SET_ERR_RET_VAL( "ReadHDF5 Failure", MB_FAILURE );
1639 
1640  return rval;
1641 }
1642 
1643 ErrorCode ReadHDF5::read_node_adj_elems( const mhdf_ElemDesc& group, hid_t table_handle, Range* handles_out )
1644 {
1646 
1647  debug_barrier();
1648 
1649  mhdf_Status status;
1650  ErrorCode rval;
1651  IODebugTrack debug_track( debugTrack, std::string( group.handle ) );
1652 
1653  // Copy data to local variables (makes other code clearer)
1654  const int node_per_elem = group.desc.vals_per_ent;
1655  long start_id = group.desc.start_id;
1656  long remaining = group.desc.count;
1657  const EntityType type = CN::EntityTypeFromName( group.type );
1658 
1659  // Figure out how many elements we can read in each pass
1660  long* const buffer = reinterpret_cast< long* >( dataBuffer );
1661  const long buffer_size = bufferSize / ( node_per_elem * sizeof( buffer[0] ) );
1662  // Read all element connectivity in buffer_size blocks
1663  long offset = 0;
1664  dbgOut.printf( 3, "Reading node-adjacent elements from \"%s\" in %ld chunks\n", group.handle,
1665  ( remaining + buffer_size - 1 ) / buffer_size );
1666  int nn = 0;
1667  Range::iterator hint;
1668  if( handles_out ) hint = handles_out->begin();
1669  while( remaining )
1670  {
1671  dbgOut.printf( 3, "Reading chunk %d of connectivity data for \"%s\"\n", ++nn, group.handle );
1672 
1673  // Read a block of connectivity data
1674  const long count = std::min( remaining, buffer_size );
1675  debug_track.record_io( offset, count );
1676  assert_range( buffer, count * node_per_elem );
1677  mhdf_readConnectivityWithOpt( table_handle, offset, count, H5T_NATIVE_LONG, buffer, collIO, &status );
1678  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1679  offset += count;
1680  remaining -= count;
1681 
1682  // Count the number of elements in the block that we want,
1683  // zero connectivity for other elements
1684  long num_elem = 0;
1685  long* iter = buffer;
1686  for( long i = 0; i < count; ++i )
1687  {
1688  for( int j = 0; j < node_per_elem; ++j )
1689  {
1690  iter[j] = (long)idMap.find( iter[j] );
1691  if( !iter[j] )
1692  {
1693  iter[0] = 0;
1694  break;
1695  }
1696  }
1697  if( iter[0] ) ++num_elem;
1698  iter += node_per_elem;
1699  }
1700 
1701  if( !num_elem )
1702  {
1703  start_id += count;
1704  continue;
1705  }
1706 
1707  // Create elements
1708  EntityHandle handle;
1709  EntityHandle* array;
1710  rval = readUtil->get_element_connect( (int)num_elem, node_per_elem, type, 0, handle, array );
1711  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1712 
1713  // Copy all non-zero connectivity values
1714  iter = buffer;
1715  EntityHandle* iter2 = array;
1716  EntityHandle h = handle;
1717  for( long i = 0; i < count; ++i )
1718  {
1719  if( !*iter )
1720  {
1721  iter += node_per_elem;
1722  continue;
1723  }
1724  if( !idMap.insert( start_id + i, h++, 1 ).second ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1725 
1726  long* const end = iter + node_per_elem;
1727  for( ; iter != end; ++iter, ++iter2 )
1728  *iter2 = (EntityHandle)*iter;
1729  }
1730  assert( iter2 - array == num_elem * node_per_elem );
1731  start_id += count;
1732 
1733  rval = readUtil->update_adjacencies( handle, num_elem, node_per_elem, array );
1734  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1735  if( handles_out ) hint = handles_out->insert( hint, handle, handle + num_elem - 1 );
1736  }
1737 
1738  debug_track.all_reduce();
1739  return MB_SUCCESS;
1740 }
1741 
1742 ErrorCode ReadHDF5::read_elems( int i, const Range& elems_in, Range& nodes )
1743 {
1745 
1746  debug_barrier();
1747  dbgOut.tprintf( 1, "READING %s CONNECTIVITY (%lu elems in %lu selects)\n", fileInfo->elems[i].handle,
1748  (unsigned long)elems_in.size(), (unsigned long)elems_in.psize() );
1749 
1750  EntityHandle* const buffer = reinterpret_cast< EntityHandle* >( dataBuffer );
1751  const int node_per_elem = fileInfo->elems[i].desc.vals_per_ent;
1752  const size_t buffer_size = bufferSize / ( node_per_elem * sizeof( EntityHandle ) );
1753 
1754  if( elems_in.empty() ) return MB_SUCCESS;
1755 
1756  assert( (long)elems_in.front() >= fileInfo->elems[i].desc.start_id );
1757  assert( (long)elems_in.back() - fileInfo->elems[i].desc.start_id < fileInfo->elems[i].desc.count );
1758 
1759  // We don't support version 3 style poly element data
1761 
1762  mhdf_Status status;
1763  hid_t table = mhdf_openConnectivitySimple( filePtr, fileInfo->elems[i].handle, &status );
1764  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1765 
1766  try
1767  {
1768  ReadHDF5Dataset reader( fileInfo->elems[i].handle, table, nativeParallel, mpiComm );
1769  reader.set_file_ids( elems_in, fileInfo->elems[i].desc.start_id, buffer_size, handleType );
1770  dbgOut.printf( 3, "Reading node list in %lu chunks for \"%s\"\n", reader.get_read_count(),
1771  fileInfo->elems[i].handle );
1772  int nn = 0;
1773  while( !reader.done() )
1774  {
1775  dbgOut.printf( 3, "Reading chunk %d of \"%s\" connectivity\n", ++nn, fileInfo->elems[i].handle );
1776  size_t num_read;
1777  reader.read( buffer, num_read );
1778  std::sort( buffer, buffer + num_read * node_per_elem );
1779  num_read = std::unique( buffer, buffer + num_read * node_per_elem ) - buffer;
1780  copy_sorted_file_ids( buffer, num_read, nodes );
1781  }
1782  }
1784  {
1785  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1786  }
1787 
1788  return MB_SUCCESS;
1789 }
1790 
1791 ErrorCode ReadHDF5::read_poly( const mhdf_ElemDesc& elems, const Range& file_ids )
1792 {
1793  class PolyReader : public ReadHDF5VarLen
1794  {
1795  private:
1796  const EntityType type;
1797  ReadHDF5* readHDF5;
1798 
1799  public:
1800  PolyReader( EntityType elem_type, void* buffer, size_t buffer_size, ReadHDF5* owner, DebugOutput& dbg )
1801  : ReadHDF5VarLen( dbg, buffer, buffer_size ), type( elem_type ), readHDF5( owner )
1802  {
1803  }
1804  virtual ~PolyReader() {}
1805  ErrorCode store_data( EntityHandle file_id, void* data, long len, bool )
1806  {
1807  size_t valid;
1808  EntityHandle* conn = reinterpret_cast< EntityHandle* >( data );
1809  readHDF5->convert_id_to_handle( conn, len, valid );
1810  if( valid != (size_t)len ) MB_CHK_ERR( MB_ENTITY_NOT_FOUND );
1811  EntityHandle handle;
1812  ErrorCode rval = readHDF5->moab()->create_element( type, conn, len, handle );
1813  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1814 
1815  rval = readHDF5->insert_in_id_map( file_id, handle );
1816  return rval;
1817  }
1818  };
1819 
1821 
1822  debug_barrier();
1823 
1824  EntityType type = CN::EntityTypeFromName( elems.type );
1825  if( type == MBMAXTYPE )
1826  {
1827  MB_SET_ERR( MB_FAILURE, "Unknown element type: \"" << elems.type << "\"" );
1828  }
1829 
1830  hid_t handles[2];
1831  mhdf_Status status;
1832  long num_poly, num_conn, first_id;
1833  mhdf_openPolyConnectivity( filePtr, elems.handle, &num_poly, &num_conn, &first_id, handles, &status );
1834  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1835 
1836  std::string nm( elems.handle );
1837  ReadHDF5Dataset offset_reader( ( nm + " offsets" ).c_str(), handles[0], nativeParallel, mpiComm, true );
1838  ReadHDF5Dataset connect_reader( ( nm + " data" ).c_str(), handles[1], nativeParallel, mpiComm, true );
1839 
1840  PolyReader tool( type, dataBuffer, bufferSize, this, dbgOut );
1841  return tool.read( offset_reader, connect_reader, file_ids, first_id, handleType );
1842 }
1843 
1845 {
1846  ErrorCode rval;
1847 
1848  // Build list of entities that we need to find the sides of
1849  Range explicit_ents;
1850  Range::iterator hint = explicit_ents.begin();
1851  for( IDMap::iterator i = idMap.begin(); i != idMap.end(); ++i )
1852  {
1853  EntityHandle start = i->value;
1854  EntityHandle end = i->value + i->count - 1;
1855  EntityType type = TYPE_FROM_HANDLE( start );
1856  assert( type == TYPE_FROM_HANDLE( end ) ); // Otherwise handle space entirely full!!
1857  if( type != MBVERTEX && type != MBENTITYSET ) hint = explicit_ents.insert( hint, start, end );
1858  }
1859  explicit_ents = subtract( explicit_ents, side_ents );
1860 
1861  // Figure out which entities we want to delete
1862  Range dead_ents( side_ents );
1863  Range::iterator ds, de, es;
1864  ds = dead_ents.lower_bound( CN::TypeDimensionMap[1].first );
1865  de = dead_ents.lower_bound( CN::TypeDimensionMap[2].first, ds );
1866  if( ds != de )
1867  {
1868  // Get subset of explicit ents of dimension greater than 1
1869  es = explicit_ents.lower_bound( CN::TypeDimensionMap[2].first );
1870  Range subset, adj;
1871  subset.insert( es, explicit_ents.end() );
1872  rval = iFace->get_adjacencies( subset, 1, false, adj, Interface::UNION );
1873  if( MB_SUCCESS != rval ) return rval;
1874  dead_ents = subtract( dead_ents, adj );
1875  }
1876  ds = dead_ents.lower_bound( CN::TypeDimensionMap[2].first );
1877  de = dead_ents.lower_bound( CN::TypeDimensionMap[3].first, ds );
1878  assert( de == dead_ents.end() );
1879  if( ds != de )
1880  {
1881  // Get subset of explicit ents of dimension 3
1882  es = explicit_ents.lower_bound( CN::TypeDimensionMap[3].first );
1883  Range subset, adj;
1884  subset.insert( es, explicit_ents.end() );
1885  rval = iFace->get_adjacencies( subset, 2, false, adj, Interface::UNION );
1886  if( MB_SUCCESS != rval ) return rval;
1887  dead_ents = subtract( dead_ents, adj );
1888  }
1889 
1890  // Now delete anything remaining in dead_ents
1891  dbgOut.printf( 2, "Deleting %lu elements\n", (unsigned long)dead_ents.size() );
1892  dbgOut.print( 4, "\tDead entities: ", dead_ents );
1893  rval = iFace->delete_entities( dead_ents );
1894  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1895 
1896  // Remove dead entities from ID map
1897  while( !dead_ents.empty() )
1898  {
1899  EntityHandle start = dead_ents.front();
1900  EntityID count = dead_ents.const_pair_begin()->second - start + 1;
1901  IDMap::iterator rit;
1902  for( rit = idMap.begin(); rit != idMap.end(); ++rit )
1903  if( rit->value <= start && (EntityID)( start - rit->value ) < rit->count ) break;
1904  if( rit == idMap.end() ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1905 
1906  EntityID offset = start - rit->value;
1907  EntityID avail = rit->count - offset;
1908  if( avail < count ) count = avail;
1909 
1910  dead_ents.erase( dead_ents.begin(), dead_ents.begin() + count );
1911  idMap.erase( rit->begin + offset, count );
1912  }
1913 
1914  return MB_SUCCESS;
1915 }
1916 
1918 {
1920 
1921  debug_barrier();
1922 
1923  mhdf_Status status;
1924  ErrorCode rval;
1925 
1926  const size_t num_sets = fileInfo->sets.count;
1927  if( !num_sets ) // If no sets at all!
1928  return MB_SUCCESS;
1929 
1930  // Create sets
1931  std::vector< unsigned > flags( file_ids.size() );
1932  Range::iterator si = file_ids.begin();
1933  for( size_t i = 0; i < flags.size(); ++i, ++si )
1934  flags[i] = setMeta[*si - fileInfo->sets.start_id][3] & ~(long)mhdf_SET_RANGE_BIT;
1935  EntityHandle start_handle;
1936  // the files ids could be empty, for empty partitions
1937  if( !file_ids.empty() )
1938  {
1939  rval = readUtil->create_entity_sets( flags.size(), &flags[0], 0, start_handle );
1940  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1941  rval = insert_in_id_map( file_ids, start_handle );
1942  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1943  }
1944 
1945  // Read contents
1947  {
1948  long len = 0;
1949  hid_t handle = mhdf_openSetData( filePtr, &len, &status );
1950  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1951 
1952  ReadHDF5Dataset dat( "set contents", handle, nativeParallel, mpiComm, true );
1953  rval = read_set_data( file_ids, start_handle, dat, CONTENT );
1954  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1955  }
1956 
1957  // Read set child lists
1959  {
1960  long len = 0;
1961  hid_t handle = mhdf_openSetChildren( filePtr, &len, &status );
1962  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1963 
1964  ReadHDF5Dataset dat( "set children", handle, nativeParallel, mpiComm, true );
1965  rval = read_set_data( file_ids, start_handle, dat, CHILD );
1966  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1967  }
1968 
1969  // Read set parent lists
1970  if( fileInfo->have_set_parents )
1971  {
1972  long len = 0;
1973  hid_t handle = mhdf_openSetParents( filePtr, &len, &status );
1974  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1975 
1976  ReadHDF5Dataset dat( "set parents", handle, nativeParallel, mpiComm, true );
1977  rval = read_set_data( file_ids, start_handle, dat, PARENT );
1978  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
1979  }
1980 
1981  return MB_SUCCESS;
1982 }
1983 
1985 {
1987 
1988  assert( !setMeta );
1989  const long num_sets = fileInfo->sets.count;
1990  if( !num_sets ) return MB_SUCCESS;
1991 
1992  mhdf_Status status;
1993  hid_t handle = mhdf_openSetMetaSimple( filePtr, &status );
1994  if( is_error( status ) )
1995  {
1996  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
1997  }
1998 
1999  // Allocate extra space if we need it for data conversion
2000  hid_t meta_type = H5Dget_type( handle );
2001  size_t size = H5Tget_size( meta_type );
2002  if( size > sizeof( long ) )
2003  setMeta = new long[( num_sets * size + ( sizeof( long ) - 1 ) ) / sizeof( long )][4];
2004  else
2005  setMeta = new long[num_sets][4];
2006 
2007  // Set some parameters based on whether or not each proc reads the
2008  // table or only the root reads it and bcasts it to the others
2009  int rank = 0;
2010  bool bcast = false;
2011  hid_t ioprop = H5P_DEFAULT;
2012 #ifdef MOAB_HAVE_MPI
2013  MPI_Comm comm = 0;
2014  if( nativeParallel )
2015  {
2016  rank = myPcomm->proc_config().proc_rank();
2017  comm = myPcomm->proc_config().proc_comm();
2018  bcast = bcastDuplicateReads;
2019  if( !bcast ) ioprop = collIO;
2020  }
2021 #endif
2022 
2023  if( !bcast || 0 == rank )
2024  {
2025  mhdf_readSetMetaWithOpt( handle, 0, num_sets, meta_type, setMeta, ioprop, &status );
2026  if( is_error( status ) )
2027  {
2028  H5Tclose( meta_type );
2029  mhdf_closeData( filePtr, handle, &status );
2030  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2031  }
2032 
2033  H5Tconvert( meta_type, H5T_NATIVE_LONG, num_sets * 4, setMeta, 0, H5P_DEFAULT );
2034  }
2035  mhdf_closeData( filePtr, handle, &status );
2036  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2037  H5Tclose( meta_type );
2038 
2039  if( bcast )
2040  {
2041 #ifdef MOAB_HAVE_MPI
2042  int ierr = MPI_Bcast( (void*)setMeta, num_sets * 4, MPI_LONG, 0, comm );
2043  if( MPI_SUCCESS != ierr ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2044 #else
2045  assert( rank == 0 ); // If not MPI, then only one proc
2046 #endif
2047  }
2048 
2049  return MB_SUCCESS;
2050 }
2051 
2052 ErrorCode ReadHDF5::read_set_ids_recursive( Range& sets_in_out, bool contained_sets, bool child_sets )
2053 {
2055  mhdf_Status status;
2056 
2057  if( !fileInfo->have_set_children ) child_sets = false;
2058  if( !fileInfo->have_set_contents ) contained_sets = false;
2059  if( !child_sets && !contained_sets ) return MB_SUCCESS;
2060 
2061  // Open data tables
2062  if( fileInfo->sets.count == 0 )
2063  {
2064  assert( sets_in_out.empty() );
2065  return MB_SUCCESS;
2066  }
2067 
2068  if( !contained_sets && !child_sets ) return MB_SUCCESS;
2069 
2070  ReadHDF5Dataset cont( "set contents", false, mpiComm );
2071  ReadHDF5Dataset child( "set children", false, mpiComm );
2072 
2073  if( contained_sets )
2074  {
2075  long content_len = 0;
2076  hid_t content_handle = mhdf_openSetData( filePtr, &content_len, &status );
2077  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2078  try
2079  {
2080  cont.init( content_handle, true );
2081  }
2083  {
2084  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2085  }
2086  }
2087 
2088  if( child_sets )
2089  {
2090  long child_len = 0;
2091  hid_t child_handle = mhdf_openSetChildren( filePtr, &child_len, &status );
2092  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2093  try
2094  {
2095  child.init( child_handle, true );
2096  }
2098  {
2099  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2100  }
2101  }
2102 
2103  ErrorCode rval = MB_SUCCESS;
2104  Range children, new_children( sets_in_out );
2105  int iteration_count = 0;
2106  do
2107  {
2108  ++iteration_count;
2109  dbgOut.tprintf( 2, "Iteration %d of read_set_ids_recursive\n", iteration_count );
2110  children.clear();
2111  if( child_sets )
2112  {
2113  rval = read_set_data( new_children, 0, child, CHILD, &children );
2114  if( MB_SUCCESS != rval ) break;
2115  }
2116  if( contained_sets )
2117  {
2118  rval = read_set_data( new_children, 0, cont, CONTENT, &children );
2119  // Remove any non-set values
2120  Range::iterator it = children.lower_bound( fileInfo->sets.start_id );
2121  children.erase( children.begin(), it );
2122  it = children.lower_bound( fileInfo->sets.start_id + fileInfo->sets.count );
2123  children.erase( it, children.end() );
2124  if( MB_SUCCESS != rval ) break;
2125  }
2126  new_children = subtract( children, sets_in_out );
2127  dbgOut.print_ints( 2, "Adding additional contained/child sets", new_children );
2128  sets_in_out.merge( new_children );
2129  } while( !new_children.empty() );
2130 
2131  return MB_SUCCESS;
2132 }
2133 
2134 ErrorCode ReadHDF5::find_sets_containing( Range& sets_out, bool read_set_containing_parents )
2135 {
2136  ErrorCode rval;
2137  mhdf_Status status;
2138 
2140 
2141  if( !fileInfo->have_set_contents ) return MB_SUCCESS;
2142  assert( fileInfo->sets.count );
2143 
2144  // Open data tables
2145  long content_len = 0;
2146  hid_t content_handle = mhdf_openSetData( filePtr, &content_len, &status );
2147  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2148 
2149  hid_t data_type = H5Dget_type( content_handle );
2150 
2151  rval = find_sets_containing( content_handle, data_type, content_len, read_set_containing_parents, sets_out );
2152 
2153  H5Tclose( data_type );
2154 
2155  mhdf_closeData( filePtr, content_handle, &status );
2156  if( MB_SUCCESS == rval && is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2157 
2158  return rval;
2159 }
2160 
2161 static bool set_map_intersect( bool ranged,
2162  const long* contents,
2163  int content_len,
2164  const RangeMap< long, EntityHandle >& id_map )
2165 {
2166  if( ranged )
2167  {
2168  if( !content_len || id_map.empty() ) return false;
2169 
2170  const long* j = contents;
2171  const long* const end = contents + content_len;
2172  assert( content_len % 2 == 0 );
2173  while( j != end )
2174  {
2175  long start = *( j++ );
2176  long count = *( j++ );
2177  if( id_map.intersects( start, count ) ) return true;
2178  }
2179  }
2180  else
2181  {
2182  const long* const end = contents + content_len;
2183  for( const long* i = contents; i != end; ++i )
2184  if( id_map.exists( *i ) ) return true;
2185  }
2186 
2187  return false;
2188 }
2189 
2191 {
2192  bool operator()( const long a1[4], const long a2[4] )
2193  {
2194  return a1[ReadHDF5::CONTENT] < a2[0];
2195  }
2196 };
2197 
2199  hid_t content_type,
2200  long contents_len,
2201  bool read_set_containing_parents,
2202  Range& file_ids )
2203 {
2205 
2206  // Scan all set contents data
2207 
2208  const size_t content_size = H5Tget_size( content_type );
2209  const long num_sets = fileInfo->sets.count;
2210  dbgOut.printf( 2, "Searching contents of %ld\n", num_sets );
2211  mhdf_Status status;
2212 
2213  int rank = 0;
2214  bool bcast = false;
2215 #ifdef MOAB_HAVE_MPI
2216  MPI_Comm comm = 0;
2217  if( nativeParallel )
2218  {
2219  rank = myPcomm->proc_config().proc_rank();
2220  comm = myPcomm->proc_config().proc_comm();
2221  bcast = bcastDuplicateReads;
2222  }
2223 #endif
2224 
2225  // Check offsets so that we don't read past end of table or
2226  // walk off end of array.
2227  long prev = -1;
2228  for( long i = 0; i < num_sets; ++i )
2229  {
2230  if( setMeta[i][CONTENT] < prev )
2231  {
2232  std::cerr << "Invalid data in set contents offsets at position " << i << ": index " << setMeta[i][CONTENT]
2233  << " is less than previous index " << prev << std::endl;
2234  std::cerr.flush();
2235  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2236  }
2237  prev = setMeta[i][CONTENT];
2238  }
2239  if( setMeta[num_sets - 1][CONTENT] >= contents_len )
2240  {
2241  std::cerr << "Maximum set content index " << setMeta[num_sets - 1][CONTENT]
2242  << " exceeds contents table length of " << contents_len << std::endl;
2243  std::cerr.flush();
2244  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2245  }
2246 
2247  // Set up buffer for reading set contents
2248  long* const content_buffer = (long*)dataBuffer;
2249  const long content_len = bufferSize / std::max( content_size, sizeof( long ) );
2250 
2251  // Scan set table
2252  Range::iterator hint = file_ids.begin();
2253  Range tmp_range;
2254  long prev_idx = -1;
2255  int mm = 0;
2256  long sets_offset = 0;
2257  long temp_content[4];
2258  while( sets_offset < num_sets )
2259  {
2260  temp_content[0] = content_len + prev_idx;
2261  long sets_count =
2262  std::lower_bound( setMeta + sets_offset, setMeta + num_sets, temp_content, SetContOffComp() ) - setMeta -
2263  sets_offset;
2264  assert( sets_count >= 0 && sets_offset + sets_count <= num_sets );
2265  if( !sets_count )
2266  { // Contents of single set don't fit in buffer
2267  long content_remaining = setMeta[sets_offset][CONTENT] - prev_idx;
2268  long content_offset = prev_idx + 1;
2269  while( content_remaining )
2270  {
2271  long content_count = content_len < content_remaining ? 2 * ( content_len / 2 ) : content_remaining;
2272  assert_range( content_buffer, content_count );
2273  dbgOut.printf( 3, "Reading chunk %d (%ld values) from set contents table\n", ++mm, content_count );
2274  if( !bcast || 0 == rank )
2275  {
2276  if( !bcast )
2277  mhdf_readSetDataWithOpt( contents_handle, content_offset, content_count, content_type,
2278  content_buffer, collIO, &status );
2279  else
2280  mhdf_readSetData( contents_handle, content_offset, content_count, content_type, content_buffer,
2281  &status );
2282  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2283 
2284  H5Tconvert( content_type, H5T_NATIVE_LONG, content_count, content_buffer, 0, H5P_DEFAULT );
2285  }
2286  if( bcast )
2287  {
2288 #ifdef MOAB_HAVE_MPI
2289  int ierr = MPI_Bcast( content_buffer, content_count, MPI_LONG, 0, comm );
2290  if( MPI_SUCCESS != ierr ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2291 #else
2292  assert( rank == 0 ); // If not MPI, then only one proc
2293 #endif
2294  }
2295 
2296  if( read_set_containing_parents )
2297  {
2298  tmp_range.clear();
2299  if( setMeta[sets_offset][3] & mhdf_SET_RANGE_BIT )
2300  tmp_range.insert( *content_buffer, *( content_buffer + 1 ) );
2301  else
2302  std::copy( content_buffer, content_buffer + content_count, range_inserter( tmp_range ) );
2303  tmp_range = intersect( tmp_range, file_ids );
2304  }
2305 
2306  if( !tmp_range.empty() || set_map_intersect( setMeta[sets_offset][3] & mhdf_SET_RANGE_BIT,
2307  content_buffer, content_count, idMap ) )
2308  {
2309  long id = fileInfo->sets.start_id + sets_offset;
2310  hint = file_ids.insert( hint, id, id );
2311  if( !nativeParallel ) // Don't stop if doing READ_PART because we need to read
2312  // collectively
2313  break;
2314  }
2315  content_remaining -= content_count;
2316  content_offset += content_count;
2317  }
2318  prev_idx = setMeta[sets_offset][CONTENT];
2319  sets_count = 1;
2320  }
2321  else if( long read_num = setMeta[sets_offset + sets_count - 1][CONTENT] - prev_idx )
2322  {
2323  assert( sets_count > 0 );
2324  assert_range( content_buffer, read_num );
2325  dbgOut.printf( 3, "Reading chunk %d (%ld values) from set contents table\n", ++mm, read_num );
2326  if( !bcast || 0 == rank )
2327  {
2328  if( !bcast )
2329  mhdf_readSetDataWithOpt( contents_handle, prev_idx + 1, read_num, content_type, content_buffer,
2330  collIO, &status );
2331  else
2332  mhdf_readSetData( contents_handle, prev_idx + 1, read_num, content_type, content_buffer, &status );
2333  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2334 
2335  H5Tconvert( content_type, H5T_NATIVE_LONG, read_num, content_buffer, 0, H5P_DEFAULT );
2336  }
2337  if( bcast )
2338  {
2339 #ifdef MOAB_HAVE_MPI
2340  int ierr = MPI_Bcast( content_buffer, read_num, MPI_LONG, 0, comm );
2341  if( MPI_SUCCESS != ierr ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2342 #else
2343  assert( rank == 0 ); // If not MPI, then only one proc
2344 #endif
2345  }
2346 
2347  long* buff_iter = content_buffer;
2348  for( long i = 0; i < sets_count; ++i )
2349  {
2350  long set_size = setMeta[i + sets_offset][CONTENT] - prev_idx;
2351  prev_idx += set_size;
2352 
2353  // Check whether contents include set already being loaded
2354  if( read_set_containing_parents )
2355  {
2356  tmp_range.clear();
2357  if( setMeta[sets_offset + i][3] & mhdf_SET_RANGE_BIT )
2358  {
2359  // put in tmp_range the contents on the set
2360  // file_ids contain at this points only other sets
2361  const long* j = buff_iter;
2362  const long* const end = buff_iter + set_size;
2363  assert( set_size % 2 == 0 );
2364  while( j != end )
2365  {
2366  long start = *( j++ );
2367  long count = *( j++ );
2368  tmp_range.insert( start, start + count - 1 );
2369  }
2370  }
2371  else
2372  std::copy( buff_iter, buff_iter + set_size, range_inserter( tmp_range ) );
2373  tmp_range = intersect( tmp_range, file_ids );
2374  }
2375 
2376  if( !tmp_range.empty() ||
2377  set_map_intersect( setMeta[sets_offset + i][3] & mhdf_SET_RANGE_BIT, buff_iter, set_size, idMap ) )
2378  {
2379  long id = fileInfo->sets.start_id + sets_offset + i;
2380  hint = file_ids.insert( hint, id, id );
2381  }
2382  buff_iter += set_size;
2383  }
2384  }
2385 
2386  sets_offset += sets_count;
2387  }
2388 
2389  return MB_SUCCESS;
2390 }
2391 
2393  int ranged,
2394  EntityHandle* contents,
2395  long length,
2396  Range& results )
2397 {
2398  if( ranged )
2399  {
2400  assert( length % 2 == 0 );
2401  for( long i = 0; i < length; i += 2 )
2402  hint = results.insert( hint, contents[i], contents[i] + contents[i + 1] - 1 );
2403  }
2404  else
2405  {
2406  std::sort( contents, contents + length );
2407  for( long i = 0; i < length; ++i )
2408  hint = results.insert( hint, contents[i] );
2409  }
2410  return hint;
2411 }
2412 
2414  EntityHandle start_handle,
2415  ReadHDF5Dataset& data,
2416  SetMode mode,
2417  Range* file_ids_out )
2418 {
2419  ErrorCode rval;
2421  Range::iterator out_hint;
2422  if( file_ids_out ) out_hint = file_ids_out->begin();
2423 
2424  // Construct range of offsets into data table at which to read
2425  // Note: all offsets are incremented by TWEAK because Range cannot
2426  // store zeros.
2427  const long TWEAK = 1;
2428  Range data_offsets;
2429  Range::iterator hint = data_offsets.begin();
2430  pi = set_file_ids.const_pair_begin();
2431  if( (long)pi->first == fileInfo->sets.start_id )
2432  {
2433  long second = pi->second - fileInfo->sets.start_id;
2434  if( setMeta[second][mode] >= 0 ) hint = data_offsets.insert( hint, TWEAK, setMeta[second][mode] + TWEAK );
2435  ++pi;
2436  }
2437  for( ; pi != set_file_ids.const_pair_end(); ++pi )
2438  {
2439  long first = pi->first - fileInfo->sets.start_id;
2440  long second = pi->second - fileInfo->sets.start_id;
2441  long idx1 = setMeta[first - 1][mode] + 1;
2442  long idx2 = setMeta[second][mode];
2443  if( idx2 >= idx1 ) hint = data_offsets.insert( hint, idx1 + TWEAK, idx2 + TWEAK );
2444  }
2445  try
2446  {
2447  data.set_file_ids( data_offsets, TWEAK, bufferSize / sizeof( EntityHandle ), handleType );
2448  }
2450  {
2451  return MB_FAILURE;
2452  }
2453 
2454  // We need to increment this for each processed set because
2455  // the sets were created in the order of the ids in file_ids.
2456  EntityHandle h = start_handle;
2457 
2458  const long ranged_flag = ( mode == CONTENT ) ? mhdf_SET_RANGE_BIT : 0;
2459 
2460  std::vector< EntityHandle > partial; // For when we read only part of the contents of a set/entity
2461  Range::const_iterator fileid_iter = set_file_ids.begin();
2462  EntityHandle* buffer = reinterpret_cast< EntityHandle* >( dataBuffer );
2463  size_t count, offset;
2464 
2465  int nn = 0;
2466  /*
2467  #ifdef MOAB_HAVE_MPI
2468  if (nativeParallel && mode==CONTENT && myPcomm->proc_config().proc_size()>1 &&
2469  data_offsets.empty())
2470  {
2471  MB_SET_ERR_CONT( "ReadHDF5 Failure: Attempt reading an empty dataset on proc " <<
2472  myPcomm->proc_config().proc_rank());
2473  MPI_Abort(myPcomm->proc_config().proc_comm(), 1);
2474  }
2475  #endif
2476  */
2477  if( ( 1 >= set_file_ids.size() ) && ( data.done() ) && moab::ReadHDF5::CONTENT == mode )
2478  // do at least one null read, it is needed in parallel
2479  data.null_read();
2480 
2481  while( !data.done() )
2482  {
2483  dbgOut.printf( 3, "Reading chunk %d of %s\n", ++nn, data.get_debug_desc() );
2484  try
2485  {
2486  data.read( buffer, count );
2487  }
2489  {
2490  return MB_FAILURE;
2491  }
2492 
2493  // Assert not appropriate here - I might have treated all my file ids, but maybe
2494  // another proc hasn't; for me, count will be zero, so I won't do anything, but
2495  // I still need to go through the motions to make the read work
2496 
2497  // Handle 'special' case where we read some, but not all
2498  // of the data for an entity during the last iteration.
2499  offset = 0;
2500  if( !partial.empty() )
2501  { // Didn't read all of previous entity
2502  assert( fileid_iter != set_file_ids.end() );
2503  size_t num_prev = partial.size();
2504  size_t idx = *fileid_iter - fileInfo->sets.start_id;
2505  size_t len = idx ? setMeta[idx][mode] - setMeta[idx - 1][mode] : setMeta[idx][mode] + 1;
2506  offset = len - num_prev;
2507  if( offset > count )
2508  { // Still don't have all
2509  partial.insert( partial.end(), buffer, buffer + count );
2510  continue;
2511  }
2512 
2513  partial.insert( partial.end(), buffer, buffer + offset );
2514  if( file_ids_out )
2515  {
2516  out_hint = copy_set_contents( out_hint, setMeta[idx][3] & ranged_flag, &partial[0], partial.size(),
2517  *file_ids_out );
2518  }
2519  else
2520  {
2521  switch( mode )
2522  {
2523  size_t valid;
2524  case CONTENT:
2525  if( setMeta[idx][3] & ranged_flag )
2526  {
2527  if( len % 2 ) MB_CHK_ERR( MB_INDEX_OUT_OF_RANGE );
2528  Range range;
2529  convert_range_to_handle( &partial[0], len / 2, range );
2530  rval = moab()->add_entities( h, range );
2531  }
2532  else
2533  {
2534  convert_id_to_handle( &partial[0], len, valid );
2535  rval = moab()->add_entities( h, &partial[0], valid );
2536  }
2537  break;
2538  case CHILD:
2539  convert_id_to_handle( &partial[0], len, valid );
2540  rval = moab()->add_child_meshsets( h, &partial[0], valid );
2541  break;
2542  case PARENT:
2543  convert_id_to_handle( &partial[0], len, valid );
2544  rval = moab()->add_parent_meshsets( h, &partial[0], valid );
2545  break;
2546  default:
2547  break;
2548  }
2549  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
2550  }
2551 
2552  ++fileid_iter;
2553  ++h;
2554  partial.clear();
2555  }
2556 
2557  // Process contents for all entities for which we
2558  // have read the complete list
2559  while( offset < count )
2560  {
2561  assert( fileid_iter != set_file_ids.end() );
2562  size_t idx = *fileid_iter - fileInfo->sets.start_id;
2563  size_t len = idx ? setMeta[idx][mode] - setMeta[idx - 1][mode] : setMeta[idx][mode] + 1;
2564  // If we did not read all of the final entity,
2565  // store what we did read to be processed in the
2566  // next iteration
2567  if( offset + len > count )
2568  {
2569  partial.insert( partial.end(), buffer + offset, buffer + count );
2570  break;
2571  }
2572 
2573  if( file_ids_out )
2574  {
2575  out_hint =
2576  copy_set_contents( out_hint, setMeta[idx][3] & ranged_flag, buffer + offset, len, *file_ids_out );
2577  }
2578  else
2579  {
2580  switch( mode )
2581  {
2582  size_t valid;
2583  case CONTENT:
2584  if( setMeta[idx][3] & ranged_flag )
2585  {
2586  if( len % 2 ) MB_CHK_ERR( MB_INDEX_OUT_OF_RANGE );
2587  Range range;
2588  convert_range_to_handle( buffer + offset, len / 2, range );
2589  rval = moab()->add_entities( h, range );
2590  }
2591  else
2592  {
2593  convert_id_to_handle( buffer + offset, len, valid );
2594  rval = moab()->add_entities( h, buffer + offset, valid );
2595  }
2596  break;
2597  case CHILD:
2598  convert_id_to_handle( buffer + offset, len, valid );
2599  rval = moab()->add_child_meshsets( h, buffer + offset, valid );
2600  break;
2601  case PARENT:
2602  convert_id_to_handle( buffer + offset, len, valid );
2603  rval = moab()->add_parent_meshsets( h, buffer + offset, valid );
2604  break;
2605  default:
2606  break;
2607  }
2608  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
2609  }
2610 
2611  ++fileid_iter;
2612  ++h;
2613  offset += len;
2614  }
2615  }
2616 
2617  return MB_SUCCESS;
2618 }
2619 
2621 {
2623 
2624  if( !fileInfo->have_set_contents ) return MB_SUCCESS;
2625  dbgOut.tprint( 2, "Reading set contained file IDs\n" );
2626  try
2627  {
2628  mhdf_Status status;
2629  long content_len;
2630  hid_t contents = mhdf_openSetData( filePtr, &content_len, &status );
2631  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2632  ReadHDF5Dataset data( "set contents", contents, nativeParallel, mpiComm, true );
2633 
2634  return read_set_data( sets, 0, data, CONTENT, &file_ids );
2635  }
2637  {
2638  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2639  }
2640 }
2641 
2642 ErrorCode ReadHDF5::read_adjacencies( hid_t table, long table_len )
2643 {
2645 
2646  ErrorCode rval;
2647  mhdf_Status status;
2648 
2649  debug_barrier();
2650 
2651  hid_t read_type = H5Dget_type( table );
2652  if( read_type < 0 ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2653  const bool convert = !H5Tequal( read_type, handleType );
2654 
2656  size_t chunk_size = bufferSize / H5Tget_size( read_type );
2657  size_t remaining = table_len;
2658  size_t left_over = 0;
2659  size_t offset = 0;
2660  dbgOut.printf( 3, "Reading adjacency list in %lu chunks\n",
2661  (unsigned long)( remaining + chunk_size - 1 ) / chunk_size );
2662  int nn = 0;
2663  while( remaining )
2664  {
2665  dbgOut.printf( 3, "Reading chunk %d of adjacency list\n", ++nn );
2666 
2667  size_t count = std::min( chunk_size, remaining );
2668  count -= left_over;
2669  remaining -= count;
2670 
2671  assert_range( buffer + left_over, count );
2672  mhdf_readAdjacencyWithOpt( table, offset, count, read_type, buffer + left_over, collIO, &status );
2673  if( is_error( status ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2674 
2675  if( convert )
2676  {
2677  herr_t err = H5Tconvert( read_type, handleType, count, buffer + left_over, 0, H5P_DEFAULT );
2678  if( err < 0 ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2679  }
2680 
2681  EntityHandle* iter = buffer;
2682  EntityHandle* end = buffer + count + left_over;
2683  while( end - iter >= 3 )
2684  {
2685  EntityHandle h = idMap.find( *iter++ );
2686  EntityHandle count2 = *iter++;
2687  if( !h )
2688  {
2689  iter += count2;
2690  continue;
2691  }
2692 
2693  if( count2 < 1 ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2694 
2695  if( end < count2 + iter )
2696  {
2697  iter -= 2;
2698  break;
2699  }
2700 
2701  size_t valid;
2702  convert_id_to_handle( iter, count2, valid, idMap );
2703  rval = iFace->add_adjacencies( h, iter, valid, false );
2704  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
2705 
2706  iter += count2;
2707  }
2708 
2709  left_over = end - iter;
2710  assert_range( (char*)buffer, left_over );
2711  assert_range( (char*)iter, left_over );
2712  memmove( buffer, iter, left_over );
2713  }
2714 
2715  assert( !left_over ); // Unexpected truncation of data
2716 
2717  return MB_SUCCESS;
2718 }
2719 
2721 {
2723 
2724  dbgOut.tprintf( 2, "Reading tag \"%s\"\n", fileInfo->tags[tag_index].name );
2725 
2726  debug_barrier();
2727 
2728  ErrorCode rval;
2729  mhdf_Status status;
2730  Tag tag = 0;
2731  hid_t read_type = -1;
2732  bool table_type;
2733  rval = create_tag( fileInfo->tags[tag_index], tag, read_type );
2734  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
2735 
2736  if( fileInfo->tags[tag_index].have_sparse )
2737  {
2738  hid_t handles[3];
2739  long num_ent, num_val;
2740  mhdf_openSparseTagData( filePtr, fileInfo->tags[tag_index].name, &num_ent, &num_val, handles, &status );
2741  if( is_error( status ) )
2742  {
2743  if( read_type ) H5Tclose( read_type );
2744  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2745  }
2746 
2747  table_type = false;
2748  if( read_type == 0 )
2749  {
2750  read_type = H5Dget_type( handles[1] );
2751  if( read_type == 0 )
2752  {
2753  mhdf_closeData( filePtr, handles[0], &status );
2754  mhdf_closeData( filePtr, handles[0], &status );
2755  if( fileInfo->tags[tag_index].size <= 0 ) mhdf_closeData( filePtr, handles[2], &status );
2756  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2757  }
2758  table_type = true;
2759  }
2760 
2761  if( fileInfo->tags[tag_index].size > 0 )
2762  {
2763  dbgOut.printf( 2, "Reading sparse data for tag \"%s\"\n", fileInfo->tags[tag_index].name );
2764  rval = read_sparse_tag( tag, read_type, handles[0], handles[1], num_ent );
2765  }
2766  else
2767  {
2768  dbgOut.printf( 2, "Reading var-len sparse data for tag \"%s\"\n", fileInfo->tags[tag_index].name );
2769  rval = read_var_len_tag( tag, read_type, handles[0], handles[1], handles[2], num_ent, num_val );
2770  }
2771 
2772  if( table_type )
2773  {
2774  H5Tclose( read_type );
2775  read_type = 0;
2776  }
2777 
2778  mhdf_closeData( filePtr, handles[0], &status );
2779  if( MB_SUCCESS == rval && is_error( status ) ) rval = MB_FAILURE;
2780  mhdf_closeData( filePtr, handles[1], &status );
2781  if( MB_SUCCESS == rval && is_error( status ) ) rval = MB_FAILURE;
2782  if( fileInfo->tags[tag_index].size <= 0 )
2783  {
2784  mhdf_closeData( filePtr, handles[2], &status );
2785  if( MB_SUCCESS == rval && is_error( status ) ) rval = MB_FAILURE;
2786  }
2787  if( MB_SUCCESS != rval )
2788  {
2789  if( read_type ) H5Tclose( read_type );
2790  MB_SET_ERR( rval, "ReadHDF5 Failure" );
2791  }
2792  }
2793 
2794  for( int j = 0; j < fileInfo->tags[tag_index].num_dense_indices; ++j )
2795  {
2796  long count;
2797  const char* name = 0;
2798  mhdf_EntDesc* desc;
2799  int elem_idx = fileInfo->tags[tag_index].dense_elem_indices[j];
2800  if( elem_idx == -2 )
2801  {
2802  desc = &fileInfo->sets;
2803  name = mhdf_set_type_handle();
2804  }
2805  else if( elem_idx == -1 )
2806  {
2807  desc = &fileInfo->nodes;
2808  name = mhdf_node_type_handle();
2809  }
2810  else if( elem_idx >= 0 && elem_idx < fileInfo->num_elem_desc )
2811  {
2812  desc = &fileInfo->elems[elem_idx].desc;
2813  name = fileInfo->elems[elem_idx].handle;
2814  }
2815  else
2816  {
2817  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2818  }
2819 
2820  dbgOut.printf( 2, "Read dense data block for tag \"%s\" on \"%s\"\n", fileInfo->tags[tag_index].name, name );
2821 
2822  hid_t handle = mhdf_openDenseTagData( filePtr, fileInfo->tags[tag_index].name, name, &count, &status );
2823  if( is_error( status ) )
2824  {
2825  rval = MB_FAILURE; // rval = error(MB_FAILURE);
2826  break;
2827  }
2828 
2829  if( count > desc->count )
2830  {
2831  mhdf_closeData( filePtr, handle, &status );
2832  MB_SET_ERR( MB_FAILURE,
2833  "Invalid data length for dense tag data: " << name << "/" << fileInfo->tags[tag_index].name );
2834  }
2835 
2836  table_type = false;
2837  if( read_type == 0 )
2838  {
2839  read_type = H5Dget_type( handle );
2840  if( read_type == 0 )
2841  {
2842  mhdf_closeData( filePtr, handle, &status );
2843  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2844  }
2845  table_type = true;
2846  }
2847 
2848  rval = read_dense_tag( tag, name, read_type, handle, desc->start_id, count );
2849 
2850  if( table_type )
2851  {
2852  H5Tclose( read_type );
2853  read_type = 0;
2854  }
2855 
2856  mhdf_closeData( filePtr, handle, &status );
2857  if( MB_SUCCESS != rval ) break;
2858  if( is_error( status ) )
2859  {
2860  rval = MB_FAILURE;
2861  break;
2862  }
2863  }
2864 
2865  if( read_type ) H5Tclose( read_type );
2866  return rval;
2867 }
2868 
2869 ErrorCode ReadHDF5::create_tag( const mhdf_TagDesc& info, Tag& handle, hid_t& hdf_type )
2870 {
2872 
2873  ErrorCode rval;
2874  mhdf_Status status;
2875  TagType storage;
2876  DataType mb_type;
2877  bool re_read_default = false;
2878 
2879  switch( info.storage )
2880  {
2881  case mhdf_DENSE_TYPE:
2882  storage = MB_TAG_DENSE;
2883  break;
2884  case mhdf_SPARSE_TYPE:
2885  storage = MB_TAG_SPARSE;
2886  break;
2887  case mhdf_BIT_TYPE:
2888  storage = MB_TAG_BIT;
2889  break;
2890  case mhdf_MESH_TYPE:
2891  storage = MB_TAG_MESH;
2892  break;
2893  default:
2894  MB_SET_ERR( MB_FAILURE, "Invalid storage type for tag '" << info.name << "': " << info.storage );
2895  }
2896 
2897  // Type-specific stuff
2898  if( info.type == mhdf_BITFIELD )
2899  {
2900  if( info.size < 1 || info.size > 8 )
2901  {
2902  MB_SET_ERR( MB_FAILURE, "Invalid bit tag: class is MB_TAG_BIT, num bits = " << info.size );
2903  }
2904  hdf_type = H5Tcopy( H5T_NATIVE_B8 );
2905  mb_type = MB_TYPE_BIT;
2906  if( hdf_type < 0 ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2907  }
2908  else if( info.type == mhdf_OPAQUE )
2909  {
2910  mb_type = MB_TYPE_OPAQUE;
2911 
2912  // Check for user-provided type
2913  Tag type_handle;
2914  std::string tag_type_name = "__hdf5_tag_type_";
2915  tag_type_name += info.name;
2916  rval = iFace->tag_get_handle( tag_type_name.c_str(), sizeof( hid_t ), MB_TYPE_OPAQUE, type_handle );
2917  if( MB_SUCCESS == rval )
2918  {
2919  EntityHandle root = 0;
2920  rval = iFace->tag_get_data( type_handle, &root, 1, &hdf_type );
2921  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
2922  hdf_type = H5Tcopy( hdf_type );
2923  re_read_default = true;
2924  }
2925  else if( MB_TAG_NOT_FOUND == rval )
2926  {
2927  hdf_type = 0;
2928  }
2929  else
2930  MB_SET_ERR( rval, "ReadHDF5 Failure" );
2931 
2932  if( hdf_type < 0 ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2933  }
2934  else
2935  {
2936  switch( info.type )
2937  {
2938  case mhdf_INTEGER:
2939  hdf_type = H5T_NATIVE_INT;
2940  mb_type = MB_TYPE_INTEGER;
2941  break;
2942  case mhdf_FLOAT:
2943  hdf_type = H5T_NATIVE_DOUBLE;
2944  mb_type = MB_TYPE_DOUBLE;
2945  break;
2946  case mhdf_BOOLEAN:
2947  hdf_type = H5T_NATIVE_UINT;
2948  mb_type = MB_TYPE_INTEGER;
2949  break;
2950  case mhdf_ENTITY_ID:
2951  hdf_type = handleType;
2952  mb_type = MB_TYPE_HANDLE;
2953  break;
2954  default:
2955  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2956  }
2957 
2958  if( info.size > 1 )
2959  { // Array
2960  hsize_t tmpsize = info.size;
2961 #if defined( H5Tarray_create_vers ) && H5Tarray_create_vers > 1
2962  hdf_type = H5Tarray_create2( hdf_type, 1, &tmpsize );
2963 #else
2964  hdf_type = H5Tarray_create( hdf_type, 1, &tmpsize, NULL );
2965 #endif
2966  }
2967  else
2968  {
2969  hdf_type = H5Tcopy( hdf_type );
2970  }
2971  if( hdf_type < 0 ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
2972  }
2973 
2974  // If default or global/mesh value in file, read it.
2975  if( info.default_value || info.global_value )
2976  {
2977  if( re_read_default )
2978  {
2979  mhdf_getTagValues( filePtr, info.name, hdf_type, info.default_value, info.global_value, &status );
2980  if( mhdf_isError( &status ) )
2981  {
2982  if( hdf_type ) H5Tclose( hdf_type );
2983  MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
2984  }
2985  }
2986 
2987  if( MB_TYPE_HANDLE == mb_type )
2988  {
2989  if( info.default_value )
2990  {
2992  if( MB_SUCCESS != rval )
2993  {
2994  if( hdf_type ) H5Tclose( hdf_type );
2995  MB_SET_ERR( rval, "ReadHDF5 Failure" );
2996  }
2997  }
2998  if( info.global_value )
2999  {
3001  if( MB_SUCCESS != rval )
3002  {
3003  if( hdf_type ) H5Tclose( hdf_type );
3004  MB_SET_ERR( rval, "ReadHDF5 Failure" );
3005  }
3006  }
3007  }
3008  }
3009 
3010  // Get tag handle, creating if necessary
3011  if( info.size < 0 )
3012  rval = iFace->tag_get_handle( info.name, info.default_value_size, mb_type, handle,
3013  storage | MB_TAG_CREAT | MB_TAG_VARLEN | MB_TAG_DFTOK, info.default_value );
3014  else
3015  rval = iFace->tag_get_handle( info.name, info.size, mb_type, handle, storage | MB_TAG_CREAT | MB_TAG_DFTOK,
3016  info.default_value );
3017  if( MB_SUCCESS != rval )
3018  {
3019  if( hdf_type ) H5Tclose( hdf_type );
3020  MB_SET_ERR( MB_FAILURE, "Tag type in file does not match type in database for \"" << info.name << "\"" );
3021  }
3022 
3023  if( info.global_value )
3024  {
3025  EntityHandle root = 0;
3026  if( info.size > 0 )
3027  { // Fixed-length tag
3028  rval = iFace->tag_set_data( handle, &root, 1, info.global_value );
3029  }
3030  else
3031  {
3032  int tag_size = info.global_value_size;
3033  rval = iFace->tag_set_by_ptr( handle, &root, 1, &info.global_value, &tag_size );
3034  }
3035  if( MB_SUCCESS != rval )
3036  {
3037  if( hdf_type ) H5Tclose( hdf_type );
3038  MB_SET_ERR( rval, "ReadHDF5 Failure" );
3039  }
3040  }
3041 
3042  return MB_SUCCESS;
3043 }
3044 
3046  const char* ent_name,
3047  hid_t hdf_read_type,
3048  hid_t data,
3049  long start_id,
3050  long num_values )
3051 {
3053 
3054  ErrorCode rval;
3055  DataType mb_type;
3056 
3057  rval = iFace->tag_get_data_type( tag_handle, mb_type );
3058  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
3059 
3060  int read_size;
3061  rval = iFace->tag_get_bytes( tag_handle, read_size );
3062  if( MB_SUCCESS != rval ) // Wrong function for variable-length tags
3063  MB_SET_ERR( rval, "ReadHDF5 Failure" );
3064  // if (MB_TYPE_BIT == mb_type)
3065  // read_size = (read_size + 7) / 8; // Convert bits to bytes, plus 7 for ceiling
3066 
3067  if( hdf_read_type )
3068  { // If not opaque
3069  hsize_t hdf_size = H5Tget_size( hdf_read_type );
3070  if( hdf_size != (hsize_t)read_size ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3071  }
3072 
3073  // Get actual entities read from file
3074  Range file_ids, handles;
3075  Range::iterator f_ins = file_ids.begin(), h_ins = handles.begin();
3076  IDMap::iterator l, u;
3077  l = idMap.lower_bound( start_id );
3078  u = idMap.lower_bound( start_id + num_values - 1 );
3079  if( l != idMap.end() && start_id + num_values > l->begin )
3080  {
3081  if( l == u )
3082  {
3083  size_t beg = std::max( start_id, l->begin );
3084  size_t end = std::min( start_id + num_values, u->begin + u->count ) - 1;
3085  f_ins = file_ids.insert( f_ins, beg, end );
3086  h_ins = handles.insert( h_ins, l->value + ( beg - l->begin ), l->value + ( end - l->begin ) );
3087  }
3088  else
3089  {
3090  size_t beg = std::max( start_id, l->begin );
3091  f_ins = file_ids.insert( f_ins, beg, l->begin + l->count - 1 );
3092  h_ins = handles.insert( h_ins, l->value + ( beg - l->begin ), l->value + l->count - 1 );
3093  for( ++l; l != u; ++l )
3094  {
3095  f_ins = file_ids.insert( f_ins, l->begin, l->begin + l->count - 1 );
3096  h_ins = handles.insert( h_ins, l->value, l->value + l->count - 1 );
3097  }
3098  if( u != idMap.end() && u->begin < start_id + num_values )
3099  {
3100  size_t end = std::min( start_id + num_values, u->begin + u->count - 1 );
3101  f_ins = file_ids.insert( f_ins, u->begin, end );
3102  h_ins = handles.insert( h_ins, u->value, u->value + end - u->begin );
3103  }
3104  }
3105  }
3106 
3107  // Given that all of the entities for this dense tag data should
3108  // have been created as a single contiguous block, the resulting
3109  // MOAB handle range should be contiguous.
3110  // THE ABOVE IS NOT NECESSARILY TRUE. SOMETIMES LOWER-DIMENSION
3111  // ENTS ARE READ AND THEN DELETED FOR PARTIAL READS.
3112  // assert(handles.empty() || handles.size() == (handles.back() - handles.front() + 1));
3113 
3114  std::string tn( "<error>" );
3115  iFace->tag_get_name( tag_handle, tn );
3116  tn += " data for ";
3117  tn += ent_name;
3118  try
3119  {
3120  h_ins = handles.begin();
3121  ReadHDF5Dataset reader( tn.c_str(), data, nativeParallel, mpiComm, false );
3122  long buffer_size = bufferSize / read_size;
3123  reader.set_file_ids( file_ids, start_id, buffer_size, hdf_read_type );
3124  dbgOut.printf( 3, "Reading dense data for tag \"%s\" and group \"%s\" in %lu chunks\n", tn.c_str(), ent_name,
3125  reader.get_read_count() );
3126  int nn = 0;
3127  while( !reader.done() )
3128  {
3129  dbgOut.printf( 3, "Reading chunk %d of \"%s\" data\n", ++nn, tn.c_str() );
3130 
3131  size_t count;
3132  reader.read( dataBuffer, count );
3133 
3134  if( MB_TYPE_HANDLE == mb_type )
3135  {
3136  rval = convert_id_to_handle( (EntityHandle*)dataBuffer, count * read_size / sizeof( EntityHandle ) );
3137  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
3138  }
3139 
3140  Range ents;
3141  Range::iterator end = h_ins;
3142  end += count;
3143  ents.insert( h_ins, end );
3144  h_ins = end;
3145 
3146  rval = iFace->tag_set_data( tag_handle, ents, dataBuffer );
3147  if( MB_SUCCESS != rval )
3148  {
3149  dbgOut.printf( 1, "Internal error setting data for tag \"%s\"\n", tn.c_str() );
3150  MB_SET_ERR( rval, "ReadHDF5 Failure" );
3151  }
3152  }
3153  }
3155  {
3156  dbgOut.printf( 1, "Internal error reading dense data for tag \"%s\"\n", tn.c_str() );
3157  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3158  }
3159 
3160  return MB_SUCCESS;
3161 }
3162 
3163 // Read entire ID table and for those file IDs corresponding
3164 // to entities that we have read from the file add both the
3165 // offset into the offset range and the handle into the handle
3166 // range. If handles are not ordered, switch to using a vector.
3168  hid_t id_table,
3169  EntityHandle start_offset, // Can't put zero in a Range
3170  Range& offset_range,
3171  Range& handle_range,
3172  std::vector< EntityHandle >& handle_vect )
3173 {
3175 
3176  offset_range.clear();
3177  handle_range.clear();
3178  handle_vect.clear();
3179 
3180  ErrorCode rval;
3181  Range::iterator handle_hint = handle_range.begin();
3182  Range::iterator offset_hint = offset_range.begin();
3183 
3185  size_t idbuf_size = bufferSize / sizeof( EntityHandle );
3186 
3187  std::string tn( name );
3188  tn += " indices";
3189 
3190  assert( start_offset > 0 ); // Can't put zero in a Range
3191  try
3192  {
3193  ReadHDF5Dataset id_reader( tn.c_str(), id_table, nativeParallel, mpiComm, false );
3194  id_reader.set_all_file_ids( idbuf_size, handleType );
3195  size_t offset = start_offset;
3196  dbgOut.printf( 3, "Reading file ids for sparse tag \"%s\" in %lu chunks\n", name, id_reader.get_read_count() );
3197  int nn = 0;
3198  while( !id_reader.done() )
3199  {
3200  dbgOut.printf( 3, "Reading chunk %d of \"%s\" IDs\n", ++nn, name );
3201  size_t count;
3202  id_reader.read( idbuf, count );
3203 
3204  rval = convert_id_to_handle( idbuf, count );
3205  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
3206 
3207  // idbuf will now contain zero-valued handles for those
3208  // tag values that correspond to entities we are not reading
3209  // from the file.
3210  for( size_t i = 0; i < count; ++i )
3211  {
3212  if( idbuf[i] )
3213  {
3214  offset_hint = offset_range.insert( offset_hint, offset + i );
3215  if( !handle_vect.empty() )
3216  {
3217  handle_vect.push_back( idbuf[i] );
3218  }
3219  else if( handle_range.empty() || idbuf[i] > handle_range.back() )
3220  {
3221  handle_hint = handle_range.insert( handle_hint, idbuf[i] );
3222  }
3223  else
3224  {
3225  handle_vect.resize( handle_range.size() );
3226  std::copy( handle_range.begin(), handle_range.end(), handle_vect.begin() );
3227  handle_range.clear();
3228  handle_vect.push_back( idbuf[i] );
3229  dbgOut.print( 2, "Switching to unordered list for tag handle list\n" );
3230  }
3231  }
3232  }
3233 
3234  offset += count;
3235  }
3236  }
3238  {
3239  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3240  }
3241 
3242  return MB_SUCCESS;
3243 }
3244 
3246  hid_t hdf_read_type,
3247  hid_t id_table,
3248  hid_t value_table,
3249  long /*num_values*/ )
3250 {
3252 
3253  // Read entire ID table and for those file IDs corresponding
3254  // to entities that we have read from the file add both the
3255  // offset into the offset range and the handle into the handle
3256  // range. If handles are not ordered, switch to using a vector.
3257  const EntityHandle base_offset = 1; // Can't put zero in a Range
3258  std::vector< EntityHandle > handle_vect;
3259  Range handle_range, offset_range;
3260  std::string tn( "<error>" );
3261  iFace->tag_get_name( tag_handle, tn );
3262  ErrorCode rval =
3263  read_sparse_tag_indices( tn.c_str(), id_table, base_offset, offset_range, handle_range, handle_vect );
3264  if( MB_SUCCESS != rval ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3265 
3266  DataType mbtype;
3267  rval = iFace->tag_get_data_type( tag_handle, mbtype );
3268  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
3269 
3270  int read_size;
3271  rval = iFace->tag_get_bytes( tag_handle, read_size );
3272  if( MB_SUCCESS != rval ) // Wrong function for variable-length tags
3273  MB_SET_ERR( rval, "ReadHDF5 Failure" );
3274  // if (MB_TYPE_BIT == mbtype)
3275  // read_size = (read_size + 7) / 8; // Convert bits to bytes, plus 7 for ceiling
3276 
3277  if( hdf_read_type )
3278  { // If not opaque
3279  hsize_t hdf_size = H5Tget_size( hdf_read_type );
3280  if( hdf_size != (hsize_t)read_size ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3281  }
3282 
3283  const int handles_per_tag = read_size / sizeof( EntityHandle );
3284 
3285  // Now read data values
3286  size_t chunk_size = bufferSize / read_size;
3287  try
3288  {
3289  ReadHDF5Dataset val_reader( ( tn + " values" ).c_str(), value_table, nativeParallel, mpiComm, false );
3290  val_reader.set_file_ids( offset_range, base_offset, chunk_size, hdf_read_type );
3291  dbgOut.printf( 3, "Reading sparse values for tag \"%s\" in %lu chunks\n", tn.c_str(),
3292  val_reader.get_read_count() );
3293  int nn = 0;
3294  size_t offset = 0;
3295  while( !val_reader.done() )
3296  {
3297  dbgOut.printf( 3, "Reading chunk %d of \"%s\" values\n", ++nn, tn.c_str() );
3298  size_t count;
3299  val_reader.read( dataBuffer, count );
3300  if( MB_TYPE_HANDLE == mbtype )
3301  {
3302  rval = convert_id_to_handle( (EntityHandle*)dataBuffer, count * handles_per_tag );
3303  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
3304  }
3305 
3306  if( !handle_vect.empty() )
3307  {
3308  rval = iFace->tag_set_data( tag_handle, &handle_vect[offset], count, dataBuffer );
3309  offset += count;
3310  }
3311  else
3312  {
3313  Range r;
3314  r.merge( handle_range.begin(), handle_range.begin() + count );
3315  handle_range.erase( handle_range.begin(), handle_range.begin() + count );
3316  rval = iFace->tag_set_data( tag_handle, r, dataBuffer );
3317  }
3318  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
3319  }
3320  }
3322  {
3323  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3324  }
3325 
3326  return MB_SUCCESS;
3327 }
3328 
3330  hid_t hdf_read_type,
3331  hid_t ent_table,
3332  hid_t val_table,
3333  hid_t off_table,
3334  long /*num_entities*/,
3335  long /*num_values*/ )
3336 {
3338 
3339  DataType mbtype;
3340 
3341  MB_CHK_SET_ERR( iFace->tag_get_data_type( tag_handle, mbtype ), "ReadHDF5 Failure" );
3342 
3343  // Can't do variable-length bit tags
3344  if( MB_TYPE_BIT == mbtype ) MB_CHK_ERR( MB_VARIABLE_DATA_LENGTH );
3345 
3346  // If here, MOAB tag must be variable-length
3347  int mbsize;
3348  if( MB_VARIABLE_DATA_LENGTH != iFace->tag_get_bytes( tag_handle, mbsize ) )
3349  MB_SET_ERR( MB_VARIABLE_DATA_LENGTH, "Not a variable tag length handle" );
3350 
3351  int read_size;
3352  if( hdf_read_type )
3353  {
3354  hsize_t hdf_size = H5Tget_size( hdf_read_type );
3355  if( hdf_size < 1 ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3356  read_size = hdf_size;
3357  }
3358  else
3359  {
3360  // Opaque
3361  read_size = 1;
3362  }
3363 
3364  std::string tn( "<error>" );
3365  iFace->tag_get_name( tag_handle, tn );
3366 
3367  // Read entire ID table and for those file IDs corresponding
3368  // to entities that we have read from the file add both the
3369  // offset into the offset range and the handle into the handle
3370  // range. If handles are not ordered, switch to using a vector.
3371  const EntityHandle base_offset = 1; // Can't put zero in a Range
3372  std::vector< EntityHandle > handle_vect;
3373  Range handle_range, offset_range;
3374  MB_CHK_SET_ERR( read_sparse_tag_indices( tn.c_str(), ent_table, base_offset, offset_range, handle_range,
3375  handle_vect ),
3376  "Reading sparse tag indices failed" );
3377 
3378  // This code only works if the id_table is an ordered list.
3379  // This assumption was also true for the previous iteration
3380  // of this code, but wasn't checked. MOAB's file writer
3381  // always writes an ordered list for id_table.
3382  if( !handle_vect.empty() )
3383  {
3384  MB_SET_ERR( MB_FAILURE, "Unordered file ids for variable length tag not supported" );
3385  }
3386 
3387  class VTReader : public ReadHDF5VarLen
3388  {
3389  Tag tagHandle;
3390  bool isHandle;
3391  size_t readSize;
3392  ReadHDF5* readHDF5;
3393 
3394  public:
3395  ErrorCode store_data( EntityHandle file_id, void* data, long count, bool )
3396  {
3397  if( isHandle )
3398  {
3399  if( readSize != sizeof( EntityHandle ) ) MB_SET_ERR( MB_FAILURE, "Invalid read size" );
3400  MB_CHK_ERR( readHDF5->convert_id_to_handle( (EntityHandle*)data, count ) );
3401  }
3402  int n = count;
3403  return readHDF5->moab()->tag_set_by_ptr( tagHandle, &file_id, 1, &data, &n );
3404  }
3405  VTReader( DebugOutput& debug_output,
3406  void* buffer,
3407  size_t buffer_size,
3408  Tag tag,
3409  bool is_handle_tag,
3410  size_t read_size1,
3411  ReadHDF5* owner )
3412  : ReadHDF5VarLen( debug_output, buffer, buffer_size ), tagHandle( tag ), isHandle( is_handle_tag ),
3413  readSize( read_size1 ), readHDF5( owner )
3414  {
3415  }
3416  };
3417 
3418  VTReader tool( dbgOut, dataBuffer, bufferSize, tag_handle, MB_TYPE_HANDLE == mbtype, read_size, this );
3419  try
3420  {
3421  // Read offsets into value table.
3422  std::vector< unsigned > counts;
3423  Range offsets;
3424  ReadHDF5Dataset off_reader( ( tn + " offsets" ).c_str(), off_table, nativeParallel, mpiComm, false );
3425  MB_CHK_SET_ERR( tool.read_offsets( off_reader, offset_range, base_offset, base_offset, offsets, counts ),
3426  "ReadHDF5 Failure" );
3427 
3428  // Read tag values
3429  Range empty;
3430  ReadHDF5Dataset val_reader( ( tn + " values" ).c_str(), val_table, nativeParallel, mpiComm, false );
3431  MB_CHK_SET_ERR( tool.read_data( val_reader, offsets, base_offset, hdf_read_type, handle_range, counts, empty ),
3432  "ReadHDF5 Failure" );
3433  }
3435  {
3436  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3437  }
3438 
3439  return MB_SUCCESS;
3440 }
3441 
3443 {
3444  convert_id_to_handle( array, size, idMap );
3445  return MB_SUCCESS;
3446 }
3447 
3449 {
3450  for( EntityHandle* const end = array + size; array != end; ++array )
3451  *array = id_map.find( *array );
3452 }
3453 
3455  size_t size,
3456  size_t& new_size,
3457  const RangeMap< long, EntityHandle >& id_map )
3458 {
3460  new_size = 0;
3461  for( size_t i = 0; i < size; ++i )
3462  {
3463  it = id_map.lower_bound( array[i] );
3464  if( it != id_map.end() && it->begin <= (long)array[i] )
3465  array[new_size++] = it->value + ( array[i] - it->begin );
3466  }
3467 }
3468 
3470  size_t num_ranges,
3471  const RangeMap< long, EntityHandle >& id_map,
3472  Range& merge )
3473 {
3475  Range::iterator hint = merge.begin();
3476  for( size_t i = 0; i < num_ranges; ++i )
3477  {
3478  long id = ranges[2 * i];
3479  const long end = id + ranges[2 * i + 1];
3480  // We assume that 'ranges' is sorted, but check just in case it isn't.
3481  if( it == id_map.end() || it->begin > id ) it = id_map.begin();
3482  it = id_map.lower_bound( it, id_map.end(), id );
3483  if( it == id_map.end() ) continue;
3484  if( id < it->begin ) id = it->begin;
3485  while( id < end )
3486  {
3487  if( id < it->begin ) id = it->begin;
3488  const long off = id - it->begin;
3489  long count = std::min( it->count - off, end - id );
3490  // It is possible that this new subrange is starting after the end
3491  // It will result in negative count, which does not make sense
3492  // We are done with this range, go to the next one
3493  if( count <= 0 ) break;
3494  hint = merge.insert( hint, it->value + off, it->value + off + count - 1 );
3495  id += count;
3496  if( id < end )
3497  {
3498  if( ++it == id_map.end() ) break;
3499  if( it->begin > end ) break;
3500  }
3501  }
3502  }
3503 }
3504 
3505 ErrorCode ReadHDF5::convert_range_to_handle( const EntityHandle* array, size_t num_ranges, Range& range )
3506 {
3507  convert_range_to_handle( array, num_ranges, idMap, range );
3508  return MB_SUCCESS;
3509 }
3510 
3512 {
3513  IDMap tmp_map;
3514  bool merge = !idMap.empty() && !file_ids.empty() && idMap.back().begin > (long)file_ids.front();
3515  IDMap& map = merge ? tmp_map : idMap;
3517  for( p = file_ids.const_pair_begin(); p != file_ids.const_pair_end(); ++p )
3518  {
3519  size_t count = p->second - p->first + 1;
3520  if( !map.insert( p->first, start_id, count ).second ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3521  start_id += count;
3522  }
3523  if( merge && !idMap.merge( tmp_map ) ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3524 
3525  return MB_SUCCESS;
3526 }
3527 
3529 {
3530  if( !idMap.insert( file_id, handle, 1 ).second ) MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3531  return MB_SUCCESS;
3532 }
3533 
3535 {
3537 
3538  mhdf_Status status;
3539  // std::vector<std::string> qa_list;
3540 
3541  int qa_len;
3542  char** qa = mhdf_readHistory( filePtr, &qa_len, &status );
3543  if( mhdf_isError( &status ) )
3544  {
3545  MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
3546  }
3547  // qa_list.resize(qa_len);
3548  for( int i = 0; i < qa_len; i++ )
3549  {
3550  // qa_list[i] = qa[i];
3551  free( qa[i] );
3552  }
3553  free( qa );
3554 
3555  /** FIX ME - how to put QA list on set?? */
3556 
3557  return MB_SUCCESS;
3558 }
3559 
3561 {
3563 
3564  // typedef int tag_type;
3565  typedef long tag_type;
3566  // change it to be able to read much bigger files (long is 64 bits ...)
3567 
3568  tag_type* buffer = reinterpret_cast< tag_type* >( dataBuffer );
3569  const long buffer_size = bufferSize / sizeof( tag_type );
3570  for( IDMap::iterator i = idMap.begin(); i != idMap.end(); ++i )
3571  {
3572  IDMap::Range range = *i;
3573 
3574  // Make sure the values will fit in the tag type
3575  IDMap::key_type rv = range.begin + ( range.count - 1 );
3576  tag_type tv = (tag_type)rv;
3577  if( (IDMap::key_type)tv != rv )
3578  {
3579  assert( false );
3580  return MB_INDEX_OUT_OF_RANGE;
3581  }
3582 
3583  while( range.count )
3584  {
3585  long count = buffer_size < range.count ? buffer_size : range.count;
3586 
3587  Range handles;
3588  handles.insert( range.value, range.value + count - 1 );
3589  range.value += count;
3590  range.count -= count;
3591  for( long j = 0; j < count; ++j )
3592  buffer[j] = (tag_type)range.begin++;
3593 
3594  ErrorCode rval = iFace->tag_set_data( tag, handles, buffer );
3595  if( MB_SUCCESS != rval ) return rval;
3596  }
3597  }
3598 
3599  return MB_SUCCESS;
3600 }
3601 
3603 {
3605 
3606  // create a tag that will not be saved, but it will be
3607  // used by visit plugin to match the sets and their file ids
3608  // it is the same type as the tag defined in ReadParallelcpp, for file id
3609  Tag setFileIdTag;
3610  long default_val = 0;
3611  ErrorCode rval = iFace->tag_get_handle( "__FILE_ID_FOR_SETS", sizeof( long ), MB_TYPE_OPAQUE, setFileIdTag,
3612  ( MB_TAG_DENSE | MB_TAG_CREAT ), &default_val );
3613 
3614  if( MB_SUCCESS != rval || 0 == setFileIdTag ) return rval;
3615  // typedef int tag_type;
3616  typedef long tag_type;
3617  // change it to be able to read much bigger files (long is 64 bits ...)
3618 
3619  tag_type* buffer = reinterpret_cast< tag_type* >( dataBuffer );
3620  const long buffer_size = bufferSize / sizeof( tag_type );
3621  for( IDMap::iterator i = idMap.begin(); i != idMap.end(); ++i )
3622  {
3623  IDMap::Range range = *i;
3624  EntityType htype = iFace->type_from_handle( range.value );
3625  if( MBENTITYSET != htype ) continue;
3626  // work only with entity sets
3627  // Make sure the values will fit in the tag type
3628  IDMap::key_type rv = range.begin + ( range.count - 1 );
3629  tag_type tv = (tag_type)rv;
3630  if( (IDMap::key_type)tv != rv )
3631  {
3632  assert( false );
3633  return MB_INDEX_OUT_OF_RANGE;
3634  }
3635 
3636  while( range.count )
3637  {
3638  long count = buffer_size < range.count ? buffer_size : range.count;
3639 
3640  Range handles;
3641  handles.insert( range.value, range.value + count - 1 );
3642  range.value += count;
3643  range.count -= count;
3644  for( long j = 0; j < count; ++j )
3645  buffer[j] = (tag_type)range.begin++;
3646 
3647  rval = iFace->tag_set_data( setFileIdTag, handles, buffer );
3648  if( MB_SUCCESS != rval ) return rval;
3649  }
3650  }
3651  return MB_SUCCESS;
3652 }
3653 
3654 ErrorCode ReadHDF5::read_tag_values( const char* file_name,
3655  const char* tag_name,
3656  const FileOptions& opts,
3657  std::vector< int >& tag_values_out,
3658  const SubsetList* subset_list )
3659 {
3660  ErrorCode rval;
3661 
3662  rval = set_up_read( file_name, opts );
3663  if( MB_SUCCESS != rval ) MB_SET_ERR( rval, "ReadHDF5 Failure" );
3664 
3665  int tag_index;
3666  rval = find_int_tag( tag_name, tag_index );
3667  if( MB_SUCCESS != rval )
3668  {
3669  clean_up_read( opts );
3670  MB_SET_ERR( rval, "ReadHDF5 Failure" );
3671  }
3672 
3673  if( subset_list )
3674  {
3675  Range file_ids;
3676  rval = get_subset_ids( subset_list->tag_list, subset_list->tag_list_length, file_ids );
3677  if( MB_SUCCESS != rval )
3678  {
3679  clean_up_read( opts );
3680  MB_SET_ERR( rval, "ReadHDF5 Failure" );
3681  }
3682 
3683  rval = read_tag_values_partial( tag_index, file_ids, tag_values_out );
3684  if( MB_SUCCESS != rval )
3685  {
3686  clean_up_read( opts );
3687  MB_SET_ERR( rval, "ReadHDF5 Failure" );
3688  }
3689  }
3690  else
3691  {
3692  rval = read_tag_values_all( tag_index, tag_values_out );
3693  if( MB_SUCCESS != rval )
3694  {
3695  clean_up_read( opts );
3696  MB_SET_ERR( rval, "ReadHDF5 Failure" );
3697  }
3698  }
3699 
3700  return clean_up_read( opts );
3701 }
3702 
3703 ErrorCode ReadHDF5::read_tag_values_partial( int tag_index, const Range& file_ids, std::vector< int >& tag_values )
3704 {
3706 
3707  mhdf_Status status;
3708  const mhdf_TagDesc& tag = fileInfo->tags[tag_index];
3709  long num_ent, num_val;
3710  size_t count;
3711  std::string tn( tag.name );
3712 
3713  // Read sparse values
3714  if( tag.have_sparse )
3715  {
3716  hid_t handles[3];
3717  mhdf_openSparseTagData( filePtr, tag.name, &num_ent, &num_val, handles, &status );
3718  if( mhdf_isError( &status ) )
3719  {
3720  MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
3721  }
3722 
3723  try
3724  {
3725  // Read all entity handles and fill 'offsets' with ranges of
3726  // offsets into the data table for entities that we want.
3727  Range offsets;
3728  long* buffer = reinterpret_cast< long* >( dataBuffer );
3729  const long buffer_size = bufferSize / sizeof( long );
3730  ReadHDF5Dataset ids( ( tn + " ids" ).c_str(), handles[0], nativeParallel, mpiComm );
3731  ids.set_all_file_ids( buffer_size, H5T_NATIVE_LONG );
3732  size_t offset = 0;
3733  dbgOut.printf( 3, "Reading sparse IDs for tag \"%s\" in %lu chunks\n", tag.name, ids.get_read_count() );
3734  int nn = 0;
3735  while( !ids.done() )
3736  {
3737  dbgOut.printf( 3, "Reading chunk %d of IDs for \"%s\"\n", ++nn, tag.name );
3738  ids.read( buffer, count );
3739 
3740  std::sort( buffer, buffer + count );
3741  Range::iterator ins = offsets.begin();
3742  Range::const_iterator i = file_ids.begin();
3743  for( size_t j = 0; j < count; ++j )
3744  {
3745  while( i != file_ids.end() && (long)*i < buffer[j] )
3746  ++i;
3747  if( i == file_ids.end() ) break;
3748  if( (long)*i == buffer[j] )
3749  {
3750  ins = offsets.insert( ins, j + offset, j + offset );
3751  }
3752  }
3753 
3754  offset += count;
3755  }
3756 
3757  tag_values.clear();
3758  tag_values.reserve( offsets.size() );
3759  const size_t data_buffer_size = bufferSize / sizeof( int );
3760  int* data_buffer = reinterpret_cast< int* >( dataBuffer );
3761  ReadHDF5Dataset vals( ( tn + " sparse vals" ).c_str(), handles[1], nativeParallel, mpiComm );
3762  vals.set_file_ids( offsets, 0, data_buffer_size, H5T_NATIVE_INT );
3763  dbgOut.printf( 3, "Reading sparse values for tag \"%s\" in %lu chunks\n", tag.name, vals.get_read_count() );
3764  nn = 0;
3765  // Should normally only have one read call, unless sparse nature
3766  // of file_ids caused reader to do something strange
3767  while( !vals.done() )
3768  {
3769  dbgOut.printf( 3, "Reading chunk %d of values for \"%s\"\n", ++nn, tag.name );
3770  vals.read( data_buffer, count );
3771  tag_values.insert( tag_values.end(), data_buffer, data_buffer + count );
3772  }
3773  }
3775  {
3776  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3777  }
3778  }
3779 
3780  std::sort( tag_values.begin(), tag_values.end() );
3781  tag_values.erase( std::unique( tag_values.begin(), tag_values.end() ), tag_values.end() );
3782 
3783  // Read dense values
3784  std::vector< int > prev_data, curr_data;
3785  for( int i = 0; i < tag.num_dense_indices; ++i )
3786  {
3787  int grp = tag.dense_elem_indices[i];
3788  const char* gname = 0;
3789  mhdf_EntDesc* desc = 0;
3790  if( grp == -1 )
3791  {
3792  gname = mhdf_node_type_handle();
3793  desc = &fileInfo->nodes;
3794  }
3795  else if( grp == -2 )
3796  {
3797  gname = mhdf_set_type_handle();
3798  desc = &fileInfo->sets;
3799  }
3800  else
3801  {
3802  assert( grp >= 0 && grp < fileInfo->num_elem_desc );
3803  gname = fileInfo->elems[grp].handle;
3804  desc = &fileInfo->elems[grp].desc;
3805  }
3806 
3807  Range::iterator s = file_ids.lower_bound( (EntityHandle)( desc->start_id ) );
3808  Range::iterator e = Range::lower_bound( s, file_ids.end(), (EntityHandle)( desc->start_id ) + desc->count );
3809  Range subset;
3810  subset.merge( s, e );
3811 
3812  hid_t handle = mhdf_openDenseTagData( filePtr, tag.name, gname, &num_val, &status );
3813  if( mhdf_isError( &status ) )
3814  {
3815  MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
3816  }
3817 
3818  try
3819  {
3820  curr_data.clear();
3821  tag_values.reserve( subset.size() );
3822  const size_t data_buffer_size = bufferSize / sizeof( int );
3823  int* data_buffer = reinterpret_cast< int* >( dataBuffer );
3824 
3825  ReadHDF5Dataset reader( ( tn + " dense vals" ).c_str(), handle, nativeParallel, mpiComm );
3826  reader.set_file_ids( subset, desc->start_id, data_buffer_size, H5T_NATIVE_INT );
3827  dbgOut.printf( 3, "Reading dense data for tag \"%s\" and group \"%s\" in %lu chunks\n", tag.name,
3828  fileInfo->elems[grp].handle, reader.get_read_count() );
3829  int nn = 0;
3830  // Should normally only have one read call, unless sparse nature
3831  // of file_ids caused reader to do something strange
3832  while( !reader.done() )
3833  {
3834  dbgOut.printf( 3, "Reading chunk %d of \"%s\"/\"%s\"\n", ++nn, tag.name, fileInfo->elems[grp].handle );
3835  reader.read( data_buffer, count );
3836  curr_data.insert( curr_data.end(), data_buffer, data_buffer + count );
3837  }
3838  }
3840  {
3841  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3842  }
3843 
3844  std::sort( curr_data.begin(), curr_data.end() );
3845  curr_data.erase( std::unique( curr_data.begin(), curr_data.end() ), curr_data.end() );
3846  prev_data.clear();
3847  tag_values.swap( prev_data );
3848  std::set_union( prev_data.begin(), prev_data.end(), curr_data.begin(), curr_data.end(),
3849  std::back_inserter( tag_values ) );
3850  }
3851 
3852  return MB_SUCCESS;
3853 }
3854 
3855 ErrorCode ReadHDF5::read_tag_values_all( int tag_index, std::vector< int >& tag_values )
3856 {
3858 
3859  mhdf_Status status;
3860  const mhdf_TagDesc& tag = fileInfo->tags[tag_index];
3861  long junk, num_val;
3862 
3863  // Read sparse values
3864  if( tag.have_sparse )
3865  {
3866  hid_t handles[3];
3867  mhdf_openSparseTagData( filePtr, tag.name, &junk, &num_val, handles, &status );
3868  if( mhdf_isError( &status ) )
3869  {
3870  MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
3871  }
3872 
3873  mhdf_closeData( filePtr, handles[0], &status );
3874  if( mhdf_isError( &status ) )
3875  {
3876  MB_SET_ERR_CONT( mhdf_message( &status ) );
3877  mhdf_closeData( filePtr, handles[1], &status );
3878  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3879  }
3880 
3881  hid_t file_type = H5Dget_type( handles[1] );
3882  tag_values.resize( num_val );
3883  mhdf_readTagValuesWithOpt( handles[1], 0, num_val, file_type, &tag_values[0], collIO, &status );
3884  if( mhdf_isError( &status ) )
3885  {
3886  MB_SET_ERR_CONT( mhdf_message( &status ) );
3887  H5Tclose( file_type );
3888  mhdf_closeData( filePtr, handles[1], &status );
3889  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3890  }
3891  H5Tconvert( file_type, H5T_NATIVE_INT, num_val, &tag_values[0], 0, H5P_DEFAULT );
3892  H5Tclose( file_type );
3893 
3894  mhdf_closeData( filePtr, handles[1], &status );
3895  if( mhdf_isError( &status ) )
3896  {
3897  MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
3898  }
3899  }
3900 
3901  std::sort( tag_values.begin(), tag_values.end() );
3902  tag_values.erase( std::unique( tag_values.begin(), tag_values.end() ), tag_values.end() );
3903 
3904  // Read dense values
3905  std::vector< int > prev_data, curr_data;
3906  for( int i = 0; i < tag.num_dense_indices; ++i )
3907  {
3908  int grp = tag.dense_elem_indices[i];
3909  const char* gname = 0;
3910  if( grp == -1 )
3911  gname = mhdf_node_type_handle();
3912  else if( grp == -2 )
3913  gname = mhdf_set_type_handle();
3914  else
3915  gname = fileInfo->elems[grp].handle;
3916  hid_t handle = mhdf_openDenseTagData( filePtr, tag.name, gname, &num_val, &status );
3917  if( mhdf_isError( &status ) )
3918  {
3919  MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
3920  }
3921 
3922  hid_t file_type = H5Dget_type( handle );
3923  curr_data.resize( num_val );
3924  mhdf_readTagValuesWithOpt( handle, 0, num_val, file_type, &curr_data[0], collIO, &status );
3925  if( mhdf_isError( &status ) )
3926  {
3927  MB_SET_ERR_CONT( mhdf_message( &status ) );
3928  H5Tclose( file_type );
3929  mhdf_closeData( filePtr, handle, &status );
3930  MB_SET_ERR( MB_FAILURE, "ReadHDF5 Failure" );
3931  }
3932 
3933  H5Tconvert( file_type, H5T_NATIVE_INT, num_val, &curr_data[0], 0, H5P_DEFAULT );
3934  H5Tclose( file_type );
3935  mhdf_closeData( filePtr, handle, &status );
3936  if( mhdf_isError( &status ) )
3937  {
3938  MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
3939  }
3940 
3941  std::sort( curr_data.begin(), curr_data.end() );
3942  curr_data.erase( std::unique( curr_data.begin(), curr_data.end() ), curr_data.end() );
3943 
3944  prev_data.clear();
3945  tag_values.swap( prev_data );
3946  std::set_union( prev_data.begin(), prev_data.end(), curr_data.begin(), curr_data.end(),
3947  std::back_inserter( tag_values ) );
3948  }
3949 
3950  return MB_SUCCESS;
3951 }
3953 {
3954 #ifdef MOAB_HAVE_MPI
3955  if( !myPcomm )
3956  {
3957  double recv[NUM_TIMES];
3958  MPI_Reduce( (void*)_times, recv, NUM_TIMES, MPI_DOUBLE, MPI_MAX, 0, myPcomm->proc_config().proc_comm() );
3959  for( int i = 0; i < NUM_TIMES; i++ )
3960  _times[i] = recv[i]; // just get the max from all of them
3961  }
3962  if( 0 == myPcomm->proc_config().proc_rank() )
3963  {
3964 #endif
3965 
3966  std::cout << "ReadHDF5: " << _times[TOTAL_TIME] << std::endl
3967  << " get set meta " << _times[SET_META_TIME] << std::endl
3968  << " partial subsets " << _times[SUBSET_IDS_TIME] << std::endl
3969  << " partition time " << _times[GET_PARTITION_TIME] << std::endl
3970  << " get set ids " << _times[GET_SET_IDS_TIME] << std::endl
3971  << " set contents " << _times[GET_SET_CONTENTS_TIME] << std::endl
3972  << " polyhedra " << _times[GET_POLYHEDRA_TIME] << std::endl
3973  << " elements " << _times[GET_ELEMENTS_TIME] << std::endl
3974  << " nodes " << _times[GET_NODES_TIME] << std::endl
3975  << " node adjacency " << _times[GET_NODEADJ_TIME] << std::endl
3976  << " side elements " << _times[GET_SIDEELEM_TIME] << std::endl
3977  << " update connectivity " << _times[UPDATECONN_TIME] << std::endl
3978  << " adjacency " << _times[ADJACENCY_TIME] << std::endl
3979  << " delete non_adj " << _times[DELETE_NON_SIDEELEM_TIME] << std::endl
3980  << " recursive sets " << _times[READ_SET_IDS_RECURS_TIME] << std::endl
3981  << " find contain_sets " << _times[FIND_SETS_CONTAINING_TIME] << std::endl
3982  << " read sets " << _times[READ_SETS_TIME] << std::endl
3983  << " read tags " << _times[READ_TAGS_TIME] << std::endl
3984  << " store file ids " << _times[STORE_FILE_IDS_TIME] << std::endl
3985  << " read qa records " << _times[READ_QA_TIME] << std::endl;
3986 
3987 #ifdef MOAB_HAVE_MPI
3988  }
3989 #endif
3990 }
3991 
3992 } // namespace moab