Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /** 00002 * MOAB, a Mesh-Oriented datABase, is a software component for creating, 00003 * storing and accessing finite element mesh data. 00004 * 00005 * Copyright 2004 Sandia Corporation. Under the terms of Contract 00006 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 00007 * retains certain rights in this software. 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 */ 00015 00016 //------------------------------------------------------------------------- 00017 // Filename : WriteHDF5.cpp 00018 // 00019 // Purpose : TSTT HDF5 Writer 00020 // 00021 // Special Notes : WriteSLAC used as template for this 00022 // 00023 // Creator : Jason Kraftcheck 00024 // 00025 // Creation Date : 04/01/04 00026 //------------------------------------------------------------------------- 00027 00028 #include <cassert> 00029 #if defined( _MSC_VER ) 00030 typedef int id_t; 00031 #elif defined( __MINGW32__ ) 00032 #include <sys/time.h> 00033 #else 00034 #include <ctime> 00035 #endif 00036 00037 #include <cstdlib> 00038 #include <cstring> 00039 #include <cstdarg> 00040 #include <limits> 00041 #include <cstdio> 00042 #include <iostream> 00043 #include "WriteHDF5.hpp" 00044 #include <H5Tpublic.h> 00045 #include <H5Ppublic.h> 00046 #include <H5Epublic.h> 00047 #include "moab/Interface.hpp" 00048 #include "Internals.hpp" 00049 #include "MBTagConventions.hpp" 00050 #include "moab/CN.hpp" 00051 #include "moab/FileOptions.hpp" 00052 #include "moab/CpuTimer.hpp" 00053 #include "IODebugTrack.hpp" 00054 #include "mhdf.h" 00055 00056 #ifndef MOAB_HAVE_HDF5 00057 #error Attempt to compile WriteHDF5 with HDF5 support disabled 00058 #endif 00059 00060 #undef BLOCKED_COORD_IO 00061 00062 #ifdef MOAB_HAVE_VALGRIND 00063 #include <valgrind/memcheck.h> 00064 00065 template < typename T > 00066 inline void VALGRIND_MAKE_VEC_UNDEFINED( std::vector< T >& v ) 00067 { 00068 (void)VALGRIND_MAKE_MEM_UNDEFINED( (T*)&v[0], v.size() * sizeof( T ) ); 00069 } 00070 00071 #else 00072 #ifndef VALGRIND_CHECK_MEM_IS_DEFINED 00073 #define VALGRIND_CHECK_MEM_IS_DEFINED( a, b ) ( (void)0 ) 00074 #endif 00075 #ifndef VALGRIND_CHECK_MEM_IS_ADDRESSABLE 00076 #define VALGRIND_CHECK_MEM_IS_ADDRESSABLE( a, b ) ( (void)0 ) 00077 #endif 00078 #ifndef VALGRIND_MAKE_MEM_UNDEFINED 00079 #define VALGRIND_MAKE_MEM_UNDEFINED( a, b ) ( (void)0 ) 00080 #endif 00081 00082 template < typename T > 00083 inline void VALGRIND_MAKE_VEC_UNDEFINED( std::vector< T >& ) 00084 { 00085 (void)VALGRIND_MAKE_MEM_UNDEFINED( 0, 0 ); 00086 } 00087 00088 #endif 00089 00090 namespace moab 00091 { 00092 00093 #define WRITE_HDF5_BUFFER_SIZE ( 40 * 1024 * 1024 ) 00094 00095 static hid_t get_id_type() 00096 { 00097 if( 8 == sizeof( WriteHDF5::wid_t ) ) 00098 { 00099 if( 8 == sizeof( long ) ) 00100 return H5T_NATIVE_ULONG; 00101 else 00102 return H5T_NATIVE_UINT64; 00103 } 00104 else if( 4 == sizeof( WriteHDF5::wid_t ) ) 00105 { 00106 if( 4 == sizeof( int ) ) 00107 return H5T_NATIVE_UINT; 00108 else 00109 return H5T_NATIVE_UINT32; 00110 } 00111 else 00112 { 00113 assert( 0 ); 00114 return (hid_t)-1; 00115 } 00116 } 00117 00118 // This is the HDF5 type used to store file IDs 00119 const hid_t WriteHDF5::id_type = get_id_type(); 00120 00121 // This function doesn't do anything useful. It's just a nice 00122 // place to set a break point to determine why the writer fails. 00123 static inline ErrorCode error( ErrorCode rval ) 00124 { 00125 return rval; 00126 } 00127 00128 // Call \c error function during HDF5 library errors to make 00129 // it easier to trap such errors in the debugger. This function 00130 // gets registered with the HDF5 library as a callback. It 00131 // works the same as the default (H5Eprint), except that it 00132 // also calls the \c error function as a no-op. 00133 #if defined( H5E_auto_t_vers ) && H5E_auto_t_vers > 1 00134 static herr_t handle_hdf5_error( hid_t stack, void* data ) 00135 { 00136 WriteHDF5::HDF5ErrorHandler* h = reinterpret_cast< WriteHDF5::HDF5ErrorHandler* >( data ); 00137 herr_t result = 0; 00138 if( h->func ) result = ( *h->func )( stack, h->data ); 00139 error( MB_FAILURE ); 00140 return result; 00141 } 00142 #else 00143 static herr_t handle_hdf5_error( void* data ) 00144 { 00145 WriteHDF5::HDF5ErrorHandler* h = reinterpret_cast< WriteHDF5::HDF5ErrorHandler* >( data ); 00146 herr_t result = 0; 00147 if( h->func ) result = ( *h->func )( h->data ); 00148 error( MB_FAILURE ); 00149 return result; 00150 } 00151 #endif 00152 00153 // Some macros to handle error checking. The 00154 // CHK_MHDF__ERR* macros check the value of an mhdf_Status 00155 // object. The CHK_MB_ERR_* check the value of an ErrorCode. 00156 // The *_0 macros accept no other arguments. The *_1 00157 // macros accept a single hdf5 handle to close on error. 00158 // The *_2 macros accept an array of two hdf5 handles to 00159 // close on error. The _*2C macros accept one hdf5 handle 00160 // to close on error and a bool and an hdf5 handle where 00161 // the latter handle is conditionally closed depending on 00162 // the value of the bool. All macros contain a "return" 00163 // statement. 00164 #define CHK_MHDF_ERR_0( A ) \ 00165 do \ 00166 { \ 00167 if( mhdf_isError( &( A ) ) ) \ 00168 { \ 00169 MB_SET_ERR_CONT( mhdf_message( &( A ) ) ); \ 00170 assert( 0 ); \ 00171 return error( MB_FAILURE ); \ 00172 } \ 00173 } while( false ) 00174 00175 #define CHK_MHDF_ERR_1( A, B ) \ 00176 do \ 00177 { \ 00178 if( mhdf_isError( &( A ) ) ) \ 00179 { \ 00180 MB_SET_ERR_CONT( mhdf_message( &( A ) ) ); \ 00181 assert( 0 ); \ 00182 mhdf_closeData( filePtr, ( B ), &( A ) ); \ 00183 return error( MB_FAILURE ); \ 00184 } \ 00185 } while( false ) 00186 00187 #define CHK_MHDF_ERR_2( A, B ) \ 00188 do \ 00189 { \ 00190 if( mhdf_isError( &( A ) ) ) \ 00191 { \ 00192 MB_SET_ERR_CONT( mhdf_message( &( A ) ) ); \ 00193 assert( 0 ); \ 00194 mhdf_closeData( filePtr, ( B )[0], &( A ) ); \ 00195 mhdf_closeData( filePtr, ( B )[1], &( A ) ); \ 00196 return error( MB_FAILURE ); \ 00197 } \ 00198 } while( false ) 00199 00200 #define CHK_MHDF_ERR_3( A, B ) \ 00201 do \ 00202 { \ 00203 if( mhdf_isError( &( A ) ) ) \ 00204 { \ 00205 MB_SET_ERR_CONT( mhdf_message( &( A ) ) ); \ 00206 assert( 0 ); \ 00207 mhdf_closeData( filePtr, ( B )[0], &( A ) ); \ 00208 mhdf_closeData( filePtr, ( B )[1], &( A ) ); \ 00209 mhdf_closeData( filePtr, ( B )[2], &( A ) ); \ 00210 return error( MB_FAILURE ); \ 00211 } \ 00212 } while( false ) 00213 00214 #define CHK_MHDF_ERR_2C( A, B, C, D ) \ 00215 do \ 00216 { \ 00217 if( mhdf_isError( &( A ) ) ) \ 00218 { \ 00219 MB_SET_ERR_CONT( mhdf_message( &( A ) ) ); \ 00220 assert( 0 ); \ 00221 mhdf_closeData( filePtr, ( B ), &( A ) ); \ 00222 if( C ) mhdf_closeData( filePtr, ( D ), &( A ) ); \ 00223 return error( MB_FAILURE ); \ 00224 } \ 00225 } while( false ) 00226 00227 #define CHK_MB_ERR_0( A ) \ 00228 do \ 00229 { \ 00230 if( MB_SUCCESS != ( A ) ) \ 00231 { \ 00232 MB_CHK_ERR_CONT( ( A ) ); \ 00233 return error( A ); \ 00234 } \ 00235 } while( false ) 00236 00237 #define CHK_MB_ERR_1( A, B, C ) \ 00238 do \ 00239 { \ 00240 if( MB_SUCCESS != ( A ) ) \ 00241 { \ 00242 MB_CHK_ERR_CONT( ( A ) ); \ 00243 mhdf_closeData( filePtr, ( B ), &( C ) ); \ 00244 assert( 0 ); \ 00245 return error( A ); \ 00246 } \ 00247 } while( false ) 00248 00249 #define CHK_MB_ERR_2( A, B, C ) \ 00250 do \ 00251 { \ 00252 if( MB_SUCCESS != ( A ) ) \ 00253 { \ 00254 MB_CHK_ERR_CONT( ( A ) ); \ 00255 mhdf_closeData( filePtr, ( B )[0], &( C ) ); \ 00256 mhdf_closeData( filePtr, ( B )[1], &( C ) ); \ 00257 write_finished(); \ 00258 assert( 0 ); \ 00259 return error( A ); \ 00260 } \ 00261 } while( false ) 00262 00263 #define CHK_MB_ERR_3( A, B, C ) \ 00264 do \ 00265 { \ 00266 if( MB_SUCCESS != ( A ) ) \ 00267 { \ 00268 MB_CHK_ERR_CONT( ( A ) ); \ 00269 mhdf_closeData( filePtr, ( B )[0], &( C ) ); \ 00270 mhdf_closeData( filePtr, ( B )[1], &( C ) ); \ 00271 mhdf_closeData( filePtr, ( B )[2], &( C ) ); \ 00272 write_finished(); \ 00273 assert( 0 ); \ 00274 return error( A ); \ 00275 } \ 00276 } while( false ) 00277 00278 #define CHK_MB_ERR_2C( A, B, C, D, E ) \ 00279 do \ 00280 { \ 00281 if( MB_SUCCESS != ( A ) ) \ 00282 { \ 00283 MB_CHK_ERR_CONT( ( A ) ); \ 00284 mhdf_closeData( filePtr, ( B ), &( E ) ); \ 00285 if( C ) mhdf_closeData( filePtr, ( D ), &( E ) ); \ 00286 write_finished(); \ 00287 assert( 0 ); \ 00288 return error( A ); \ 00289 } \ 00290 } while( false ) 00291 00292 #define debug_barrier() debug_barrier_line( __LINE__ ) 00293 void WriteHDF5::debug_barrier_line( int ) {} 00294 00295 class CheckOpenWriteHDF5Handles 00296 { 00297 int fileline; 00298 mhdf_FileHandle handle; 00299 int enter_count; 00300 00301 public: 00302 CheckOpenWriteHDF5Handles( mhdf_FileHandle file, int line ) 00303 : fileline( line ), handle( file ), enter_count( mhdf_countOpenHandles( file ) ) 00304 { 00305 } 00306 00307 ~CheckOpenWriteHDF5Handles() 00308 { 00309 int new_count = mhdf_countOpenHandles( handle ); 00310 if( new_count != enter_count ) 00311 { 00312 std::cout << "Leaked HDF5 object handle in function at " << __FILE__ << ":" << fileline << std::endl 00313 << "Open at entrance: " << enter_count << std::endl 00314 << "Open at exit: " << new_count << std::endl; 00315 } 00316 } 00317 }; 00318 00319 MPEState WriteHDF5::topState; 00320 MPEState WriteHDF5::subState; 00321 00322 #ifdef NDEBUG 00323 #define CHECK_OPEN_HANDLES 00324 #else 00325 #define CHECK_OPEN_HANDLES CheckOpenWriteHDF5Handles check_open_handles_( filePtr, __LINE__ ) 00326 #endif 00327 00328 bool WriteHDF5::convert_handle_tag( const EntityHandle* source, EntityHandle* dest, size_t count ) const 00329 { 00330 bool some_valid = false; 00331 for( size_t i = 0; i < count; ++i ) 00332 { 00333 if( !source[i] ) 00334 dest[i] = 0; 00335 else 00336 { 00337 dest[i] = idMap.find( source[i] ); 00338 if( dest[i] ) some_valid = true; 00339 } 00340 } 00341 00342 return some_valid; 00343 } 00344 00345 bool WriteHDF5::convert_handle_tag( EntityHandle* data, size_t count ) const 00346 { 00347 assert( sizeof( EntityHandle ) == sizeof( wid_t ) ); 00348 return convert_handle_tag( data, data, count ); 00349 } 00350 00351 ErrorCode WriteHDF5::assign_ids( const Range& entities, wid_t id ) 00352 { 00353 Range::const_pair_iterator pi; 00354 for( pi = entities.const_pair_begin(); pi != entities.const_pair_end(); ++pi ) 00355 { 00356 const EntityHandle n = pi->second - pi->first + 1; 00357 dbgOut.printf( 3, "Assigning %s %lu to %lu to file IDs [%lu,%lu]\n", 00358 CN::EntityTypeName( TYPE_FROM_HANDLE( pi->first ) ), 00359 (unsigned long)( ID_FROM_HANDLE( pi->first ) ), 00360 (unsigned long)( ID_FROM_HANDLE( pi->first ) + n - 1 ), (unsigned long)id, 00361 (unsigned long)( id + n - 1 ) ); 00362 if( TYPE_FROM_HANDLE( pi->first ) == MBPOLYGON || TYPE_FROM_HANDLE( pi->first ) == MBPOLYHEDRON ) 00363 { 00364 int num_vertices = 0; 00365 const EntityHandle* conn = 0; 00366 iFace->get_connectivity( pi->first, conn, num_vertices ); 00367 dbgOut.printf( 3, " poly with %d verts/faces \n", num_vertices ); 00368 } 00369 if( !idMap.insert( pi->first, id, n ).second ) return error( MB_FAILURE ); 00370 id += n; 00371 } 00372 00373 return MB_SUCCESS; 00374 } 00375 00376 const char* WriteHDF5::ExportSet::name() const 00377 { 00378 static char buffer[128]; 00379 switch( type ) 00380 { 00381 case MBVERTEX: 00382 return mhdf_node_type_handle(); 00383 case MBENTITYSET: 00384 return mhdf_set_type_handle(); 00385 default: 00386 sprintf( buffer, "%s%d", CN::EntityTypeName( type ), num_nodes ); 00387 return buffer; 00388 } 00389 } 00390 00391 WriterIface* WriteHDF5::factory( Interface* iface ) 00392 { 00393 return new WriteHDF5( iface ); 00394 } 00395 00396 WriteHDF5::WriteHDF5( Interface* iface ) 00397 : bufferSize( WRITE_HDF5_BUFFER_SIZE ), dataBuffer( 0 ), iFace( iface ), writeUtil( 0 ), filePtr( 0 ), 00398 setContentsOffset( 0 ), setChildrenOffset( 0 ), setParentsOffset( 0 ), maxNumSetContents( 0 ), 00399 maxNumSetChildren( 0 ), maxNumSetParents( 0 ), writeSets( false ), writeSetContents( false ), 00400 writeSetChildren( false ), writeSetParents( false ), parallelWrite( false ), collectiveIO( false ), 00401 writeTagDense( false ), writeProp( H5P_DEFAULT ), dbgOut( "H5M", stderr ), debugTrack( false ) 00402 { 00403 } 00404 00405 ErrorCode WriteHDF5::init() 00406 { 00407 ErrorCode rval; 00408 00409 if( writeUtil ) // init has already been called 00410 return MB_SUCCESS; 00411 /* 00412 #ifdef DEBUG 00413 H5Eset_auto(&hdf_error_handler, writeUtil); // HDF5 callback for errors 00414 #endif 00415 */ 00416 // For known tag types, store the corresponding HDF5 in which 00417 // the tag data is to be written in the file. 00418 // register_known_tag_types(iFace); 00419 00420 // Get the util interface 00421 rval = iFace->query_interface( writeUtil ); 00422 CHK_MB_ERR_0( rval ); 00423 00424 idMap.clear(); 00425 00426 #if defined( H5Eget_auto_vers ) && H5Eget_auto_vers > 1 00427 herr_t err = H5Eget_auto( H5E_DEFAULT, &errorHandler.func, &errorHandler.data ); 00428 #else 00429 herr_t err = H5Eget_auto( &errorHandler.func, &errorHandler.data ); 00430 #endif 00431 if( err < 0 ) 00432 { 00433 errorHandler.func = 0; 00434 errorHandler.data = 0; 00435 } 00436 else 00437 { 00438 #if defined( H5Eset_auto_vers ) && H5Eset_auto_vers > 1 00439 err = H5Eset_auto( H5E_DEFAULT, &handle_hdf5_error, &errorHandler ); 00440 #else 00441 err = H5Eset_auto( &handle_hdf5_error, &errorHandler ); 00442 #endif 00443 if( err < 0 ) 00444 { 00445 errorHandler.func = 0; 00446 errorHandler.data = 0; 00447 } 00448 } 00449 00450 if( !topState.valid() ) topState = MPEState( "WriteHDF5", "yellow" ); 00451 if( !subState.valid() ) subState = MPEState( "WriteHDF5 subevent", "cyan" ); 00452 00453 return MB_SUCCESS; 00454 } 00455 00456 ErrorCode WriteHDF5::write_finished() 00457 { 00458 // Release memory allocated in lists 00459 exportList.clear(); 00460 nodeSet.range.clear(); 00461 setSet.range.clear(); 00462 tagList.clear(); 00463 idMap.clear(); 00464 00465 HDF5ErrorHandler handler; 00466 #if defined( H5Eget_auto_vers ) && H5Eget_auto_vers > 1 00467 herr_t err = H5Eget_auto( H5E_DEFAULT, &handler.func, &handler.data ); 00468 #else 00469 herr_t err = H5Eget_auto( &handler.func, &handler.data ); 00470 #endif 00471 if( err >= 0 && handler.func == &handle_hdf5_error ) 00472 { 00473 assert( handler.data == &errorHandler ); 00474 #if defined( H5Eget_auto_vers ) && H5Eget_auto_vers > 1 00475 H5Eset_auto( H5E_DEFAULT, errorHandler.func, errorHandler.data ); 00476 #else 00477 H5Eset_auto( errorHandler.func, errorHandler.data ); 00478 #endif 00479 } 00480 00481 return MB_SUCCESS; 00482 } 00483 00484 WriteHDF5::~WriteHDF5() 00485 { 00486 if( !writeUtil ) // init() failed. 00487 return; 00488 00489 iFace->release_interface( writeUtil ); 00490 } 00491 00492 ErrorCode WriteHDF5::write_file( const char* filename, 00493 bool overwrite, 00494 const FileOptions& opts, 00495 const EntityHandle* set_array, 00496 const int num_sets, 00497 const std::vector< std::string >& qa_records, 00498 const Tag* tag_list, 00499 int num_tags, 00500 int user_dimension ) 00501 { 00502 mhdf_Status status; 00503 00504 parallelWrite = false; 00505 collectiveIO = false; 00506 00507 // Enable debug output 00508 int tmpval = 0; 00509 if( MB_SUCCESS == opts.get_int_option( "DEBUG_IO", 1, tmpval ) ) dbgOut.set_verbosity( tmpval ); 00510 00511 // writeTagDense = (MB_SUCCESS == opts.get_null_option("DENSE_TAGS")); 00512 writeTagDense = true; 00513 00514 // Enable some extra checks for reads. Note: amongst other things this 00515 // will print errors if the entire file is not read, so if doing a 00516 // partial read that is not a parallel read, this should be disabled. 00517 debugTrack = ( MB_SUCCESS == opts.get_null_option( "DEBUG_BINIO" ) ); 00518 00519 bufferSize = WRITE_HDF5_BUFFER_SIZE; 00520 int buf_size; 00521 ErrorCode rval = opts.get_int_option( "BUFFER_SIZE", buf_size ); 00522 if( MB_SUCCESS == rval && buf_size >= 24 ) bufferSize = buf_size; 00523 00524 // Allocate internal buffer to use when gathering data to write. 00525 dataBuffer = (char*)malloc( bufferSize ); 00526 if( !dataBuffer ) return error( MB_MEMORY_ALLOCATION_FAILED ); 00527 00528 // Clear filePtr so we know if it is open upon failure 00529 filePtr = 0; 00530 00531 // Do actual write. 00532 writeProp = H5P_DEFAULT; 00533 ErrorCode result = write_file_impl( filename, overwrite, opts, set_array, num_sets, qa_records, tag_list, num_tags, 00534 user_dimension ); 00535 // Close writeProp if it was opened 00536 if( writeProp != H5P_DEFAULT ) H5Pclose( writeProp ); 00537 00538 // Free memory buffer 00539 free( dataBuffer ); 00540 dataBuffer = 0; 00541 00542 // Close file 00543 bool created_file = false; 00544 if( filePtr ) 00545 { 00546 created_file = true; 00547 mhdf_closeFile( filePtr, &status ); 00548 filePtr = 0; 00549 if( mhdf_isError( &status ) ) 00550 { 00551 MB_SET_ERR_CONT( mhdf_message( &status ) ); 00552 if( MB_SUCCESS == result ) result = MB_FAILURE; 00553 } 00554 } 00555 00556 // Release other resources 00557 if( MB_SUCCESS == result ) 00558 result = write_finished(); 00559 else 00560 write_finished(); 00561 00562 // If write failed, remove file unless KEEP option was specified 00563 if( MB_SUCCESS != result && created_file && MB_ENTITY_NOT_FOUND == opts.get_null_option( "KEEP" ) ) 00564 remove( filename ); 00565 00566 return result; 00567 } 00568 00569 ErrorCode WriteHDF5::write_file_impl( const char* filename, 00570 bool overwrite, 00571 const FileOptions& opts, 00572 const EntityHandle* set_array, 00573 const int num_sets, 00574 const std::vector< std::string >& qa_records, 00575 const Tag* tag_list, 00576 int num_tags, 00577 int user_dimension ) 00578 { 00579 ErrorCode result; 00580 std::list< TagDesc >::const_iterator t_itor; 00581 std::list< ExportSet >::iterator ex_itor; 00582 EntityHandle elem_count, max_id; 00583 double times[NUM_TIMES] = { 0 }; 00584 00585 if( MB_SUCCESS != init() ) return error( MB_FAILURE ); 00586 00587 // See if we need to report times 00588 bool cputime = false; 00589 result = opts.get_null_option( "CPUTIME" ); 00590 if( MB_SUCCESS == result ) cputime = true; 00591 00592 CpuTimer timer; 00593 00594 dbgOut.tprint( 1, "Gathering Mesh\n" ); 00595 topState.start( "gathering mesh" ); 00596 00597 // Gather mesh to export 00598 exportList.clear(); 00599 if( 0 == num_sets || ( 1 == num_sets && set_array[0] == 0 ) ) 00600 { 00601 result = gather_all_mesh(); 00602 topState.end( result ); 00603 CHK_MB_ERR_0( result ); 00604 } 00605 else 00606 { 00607 std::vector< EntityHandle > passed_export_list( set_array, set_array + num_sets ); 00608 result = gather_mesh_info( passed_export_list ); 00609 topState.end( result ); 00610 CHK_MB_ERR_0( result ); 00611 } 00612 00613 times[GATHER_TIME] = timer.time_elapsed(); 00614 00615 // if (nodeSet.range.size() == 0) 00616 // return error(MB_ENTITY_NOT_FOUND); 00617 00618 dbgOut.tprint( 1, "Checking ID space\n" ); 00619 00620 // Make sure ID space is sufficient 00621 elem_count = nodeSet.range.size() + setSet.range.size(); 00622 for( ex_itor = exportList.begin(); ex_itor != exportList.end(); ++ex_itor ) 00623 elem_count += ex_itor->range.size(); 00624 max_id = (EntityHandle)1 << ( 8 * sizeof( wid_t ) - 1 ); 00625 if( elem_count > max_id ) 00626 { 00627 MB_SET_ERR_CONT( "ID space insufficient for mesh size" ); 00628 return error( result ); 00629 } 00630 00631 dbgOut.tprint( 1, "Creating File\n" ); 00632 00633 // Figure out the dimension in which to write the mesh. 00634 int mesh_dim; 00635 result = iFace->get_dimension( mesh_dim ); 00636 CHK_MB_ERR_0( result ); 00637 00638 if( user_dimension < 1 ) user_dimension = mesh_dim; 00639 user_dimension = user_dimension > mesh_dim ? mesh_dim : user_dimension; 00640 00641 // Create the file layout, including all tables (zero-ed) and 00642 // all structure and meta information. 00643 const char* optnames[] = { "WRITE_PART", "FORMAT", 0 }; 00644 int junk; 00645 parallelWrite = ( MB_SUCCESS == opts.match_option( "PARALLEL", optnames, junk ) ); 00646 if( parallelWrite ) 00647 { 00648 // Just store Boolean value based on string option here. 00649 // parallel_create_file will set writeProp accordingly. 00650 // collectiveIO = (MB_SUCCESS == opts.get_null_option("COLLECTIVE")); 00651 // dbgOut.printf(2, "'COLLECTIVE' option = %s\n", collectiveIO ? "YES" : "NO"); 00652 // Do this all the time, as it appears to be much faster than indep in some cases 00653 collectiveIO = true; 00654 result = 00655 parallel_create_file( filename, overwrite, qa_records, opts, tag_list, num_tags, user_dimension, times ); 00656 } 00657 else 00658 { 00659 result = serial_create_file( filename, overwrite, qa_records, tag_list, num_tags, user_dimension ); 00660 } 00661 if( MB_SUCCESS != result ) return error( result ); 00662 00663 times[CREATE_TIME] = timer.time_elapsed(); 00664 00665 dbgOut.tprint( 1, "Writing Nodes.\n" ); 00666 // Write node coordinates 00667 if( !nodeSet.range.empty() || parallelWrite ) 00668 { 00669 topState.start( "writing coords" ); 00670 result = write_nodes(); 00671 topState.end( result ); 00672 if( MB_SUCCESS != result ) return error( result ); 00673 } 00674 00675 times[COORD_TIME] = timer.time_elapsed(); 00676 00677 dbgOut.tprint( 1, "Writing connectivity.\n" ); 00678 00679 // Write element connectivity 00680 for( ex_itor = exportList.begin(); ex_itor != exportList.end(); ++ex_itor ) 00681 { 00682 topState.start( "writing connectivity for ", ex_itor->name() ); 00683 result = write_elems( *ex_itor ); 00684 topState.end( result ); 00685 if( MB_SUCCESS != result ) return error( result ); 00686 } 00687 times[CONN_TIME] = timer.time_elapsed(); 00688 00689 dbgOut.tprint( 1, "Writing sets.\n" ); 00690 00691 // Write meshsets 00692 result = write_sets( times ); 00693 if( MB_SUCCESS != result ) return error( result ); 00694 debug_barrier(); 00695 00696 times[SET_TIME] = timer.time_elapsed(); 00697 dbgOut.tprint( 1, "Writing adjacencies.\n" ); 00698 00699 // Write adjacencies 00700 // Tim says don't save node adjacencies! 00701 #ifdef MB_H5M_WRITE_NODE_ADJACENCIES 00702 result = write_adjacencies( nodeSet ); 00703 if( MB_SUCCESS != result ) return error( result ); 00704 #endif 00705 for( ex_itor = exportList.begin(); ex_itor != exportList.end(); ++ex_itor ) 00706 { 00707 topState.start( "writing adjacencies for ", ex_itor->name() ); 00708 result = write_adjacencies( *ex_itor ); 00709 topState.end( result ); 00710 if( MB_SUCCESS != result ) return error( result ); 00711 } 00712 times[ADJ_TIME] = timer.time_elapsed(); 00713 00714 dbgOut.tprint( 1, "Writing tags.\n" ); 00715 00716 // Write tags 00717 for( t_itor = tagList.begin(); t_itor != tagList.end(); ++t_itor ) 00718 { 00719 std::string name; 00720 iFace->tag_get_name( t_itor->tag_id, name ); 00721 topState.start( "writing tag: ", name.c_str() ); 00722 result = write_tag( *t_itor, times ); 00723 topState.end( result ); 00724 if( MB_SUCCESS != result ) return error( result ); 00725 } 00726 times[TAG_TIME] = timer.time_elapsed(); 00727 00728 times[TOTAL_TIME] = timer.time_since_birth(); 00729 00730 if( cputime ) 00731 { 00732 print_times( times ); 00733 } 00734 00735 return MB_SUCCESS; 00736 } 00737 00738 ErrorCode WriteHDF5::initialize_mesh( const Range ranges[5] ) 00739 { 00740 ErrorCode rval; 00741 00742 if( !ranges[0].all_of_type( MBVERTEX ) ) return error( MB_FAILURE ); 00743 nodeSet.range = ranges[0]; 00744 nodeSet.type = MBVERTEX; 00745 nodeSet.num_nodes = 1; 00746 nodeSet.max_num_ents = nodeSet.max_num_adjs = 0; 00747 00748 if( !ranges[4].all_of_type( MBENTITYSET ) ) return error( MB_FAILURE ); 00749 setSet.range = ranges[4]; 00750 setSet.type = MBENTITYSET; 00751 setSet.num_nodes = 0; 00752 setSet.max_num_ents = setSet.max_num_adjs = 0; 00753 maxNumSetContents = maxNumSetChildren = maxNumSetParents = 0; 00754 00755 exportList.clear(); 00756 std::vector< Range > bins( 1024 ); // Sort entities by connectivity length 00757 // Resize is expensive due to Range copy, so start big 00758 for( EntityType type = MBEDGE; type < MBENTITYSET; ++type ) 00759 { 00760 ExportSet set; 00761 set.max_num_ents = set.max_num_adjs = 0; 00762 const int dim = CN::Dimension( type ); 00763 00764 // Group entities by connectivity length 00765 bins.clear(); 00766 assert( dim >= 0 && dim <= 4 ); 00767 std::pair< Range::const_iterator, Range::const_iterator > p = ranges[dim].equal_range( type ); 00768 Range::const_iterator i = p.first; 00769 while( i != p.second ) 00770 { 00771 Range::const_iterator first = i; 00772 EntityHandle const* conn; 00773 int len, firstlen; 00774 00775 // Dummy storage vector for structured mesh "get_connectivity" function 00776 std::vector< EntityHandle > storage; 00777 00778 rval = iFace->get_connectivity( *i, conn, firstlen, false, &storage ); 00779 if( MB_SUCCESS != rval ) return error( rval ); 00780 00781 for( ++i; i != p.second; ++i ) 00782 { 00783 rval = iFace->get_connectivity( *i, conn, len, false, &storage ); 00784 if( MB_SUCCESS != rval ) return error( rval ); 00785 00786 if( len != firstlen ) break; 00787 } 00788 00789 if( firstlen >= (int)bins.size() ) bins.resize( firstlen + 1 ); 00790 bins[firstlen].merge( first, i ); 00791 } 00792 // Create ExportSet for each group 00793 for( std::vector< Range >::iterator j = bins.begin(); j != bins.end(); ++j ) 00794 { 00795 if( j->empty() ) continue; 00796 00797 set.range.clear(); 00798 set.type = type; 00799 set.num_nodes = j - bins.begin(); 00800 exportList.push_back( set ); 00801 exportList.back().range.swap( *j ); 00802 } 00803 } 00804 00805 return MB_SUCCESS; 00806 } 00807 00808 // Gather the mesh to be written from a list of owning meshsets. 00809 ErrorCode WriteHDF5::gather_mesh_info( const std::vector< EntityHandle >& export_sets ) 00810 { 00811 ErrorCode rval; 00812 00813 int dim; 00814 Range range; // Temporary storage 00815 Range ranges[5]; // Lists of entities to export, grouped by dimension 00816 00817 // Gather list of all related sets 00818 std::vector< EntityHandle > stack( export_sets ); 00819 std::copy( export_sets.begin(), export_sets.end(), stack.begin() ); 00820 std::vector< EntityHandle > set_children; 00821 while( !stack.empty() ) 00822 { 00823 EntityHandle meshset = stack.back(); 00824 stack.pop_back(); 00825 ranges[4].insert( meshset ); 00826 00827 // Get contained sets 00828 range.clear(); 00829 rval = iFace->get_entities_by_type( meshset, MBENTITYSET, range ); 00830 CHK_MB_ERR_0( rval ); 00831 for( Range::iterator ritor = range.begin(); ritor != range.end(); ++ritor ) 00832 { 00833 if( ranges[4].find( *ritor ) == ranges[4].end() ) stack.push_back( *ritor ); 00834 } 00835 00836 // Get child sets 00837 set_children.clear(); 00838 rval = iFace->get_child_meshsets( meshset, set_children, 1 ); 00839 CHK_MB_ERR_0( rval ); 00840 for( std::vector< EntityHandle >::iterator vitor = set_children.begin(); vitor != set_children.end(); ++vitor ) 00841 { 00842 if( ranges[4].find( *vitor ) == ranges[4].end() ) stack.push_back( *vitor ); 00843 } 00844 } 00845 00846 // Gather list of all mesh entities from list of sets, 00847 // grouped by dimension. 00848 for( Range::iterator setitor = ranges[4].begin(); setitor != ranges[4].end(); ++setitor ) 00849 { 00850 for( dim = 0; dim < 4; ++dim ) 00851 { 00852 range.clear(); 00853 rval = iFace->get_entities_by_dimension( *setitor, dim, range, false ); 00854 CHK_MB_ERR_0( rval ); 00855 00856 ranges[dim].merge( range ); 00857 } 00858 } 00859 00860 // For each list of elements, append adjacent children and 00861 // nodes to lists. 00862 for( dim = 3; dim > 0; --dim ) 00863 { 00864 for( int cdim = 1; cdim < dim; ++cdim ) 00865 { 00866 range.clear(); 00867 rval = iFace->get_adjacencies( ranges[dim], cdim, false, range ); 00868 CHK_MB_ERR_0( rval ); 00869 ranges[cdim].merge( range ); 00870 } 00871 range.clear(); 00872 rval = writeUtil->gather_nodes_from_elements( ranges[dim], 0, range ); 00873 CHK_MB_ERR_0( rval ); 00874 ranges[0].merge( range ); 00875 } 00876 00877 return initialize_mesh( ranges ); 00878 } 00879 00880 // Gather all the mesh and related information to be written. 00881 ErrorCode WriteHDF5::gather_all_mesh() 00882 { 00883 ErrorCode rval; 00884 Range ranges[5]; 00885 00886 rval = iFace->get_entities_by_type( 0, MBVERTEX, ranges[0] ); 00887 if( MB_SUCCESS != rval ) return error( rval ); 00888 00889 rval = iFace->get_entities_by_dimension( 0, 1, ranges[1] ); 00890 if( MB_SUCCESS != rval ) return error( rval ); 00891 00892 rval = iFace->get_entities_by_dimension( 0, 2, ranges[2] ); 00893 if( MB_SUCCESS != rval ) return error( rval ); 00894 00895 rval = iFace->get_entities_by_dimension( 0, 3, ranges[3] ); 00896 if( MB_SUCCESS != rval ) return error( rval ); 00897 00898 rval = iFace->get_entities_by_type( 0, MBENTITYSET, ranges[4] ); 00899 if( MB_SUCCESS != rval ) return error( rval ); 00900 00901 return initialize_mesh( ranges ); 00902 } 00903 00904 ErrorCode WriteHDF5::write_nodes() 00905 { 00906 mhdf_Status status; 00907 int dim, mesh_dim; 00908 ErrorCode rval; 00909 hid_t node_table; 00910 long first_id, num_nodes; 00911 00912 if( !nodeSet.total_num_ents ) return MB_SUCCESS; // No nodes! 00913 00914 CHECK_OPEN_HANDLES; 00915 00916 rval = iFace->get_dimension( mesh_dim ); 00917 CHK_MB_ERR_0( rval ); 00918 00919 debug_barrier(); 00920 dbgOut.print( 3, "Opening Node Coords\n" ); 00921 node_table = mhdf_openNodeCoords( filePtr, &num_nodes, &dim, &first_id, &status ); 00922 CHK_MHDF_ERR_0( status ); 00923 IODebugTrack track( debugTrack, "nodes", num_nodes ); 00924 00925 double* buffer = (double*)dataBuffer; 00926 #ifdef BLOCKED_COORD_IO 00927 int chunk_size = bufferSize / sizeof( double ); 00928 #else 00929 int chunk_size = bufferSize / ( 3 * sizeof( double ) ); 00930 #endif 00931 00932 long remaining = nodeSet.range.size(); 00933 long num_writes = ( remaining + chunk_size - 1 ) / chunk_size; 00934 if( nodeSet.max_num_ents ) 00935 { 00936 assert( nodeSet.max_num_ents >= remaining ); 00937 num_writes = ( nodeSet.max_num_ents + chunk_size - 1 ) / chunk_size; 00938 } 00939 long remaining_writes = num_writes; 00940 00941 long offset = nodeSet.offset; 00942 Range::const_iterator iter = nodeSet.range.begin(); 00943 dbgOut.printf( 3, "Writing %ld nodes in %ld blocks of %d\n", remaining, ( remaining + chunk_size - 1 ) / chunk_size, 00944 chunk_size ); 00945 while( remaining ) 00946 { 00947 (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 00948 long count = chunk_size < remaining ? chunk_size : remaining; 00949 remaining -= count; 00950 Range::const_iterator end = iter; 00951 end += count; 00952 00953 #ifdef BLOCKED_COORD_IO 00954 for( int d = 0; d < dim; d++ ) 00955 { 00956 if( d < mesh_dim ) 00957 { 00958 rval = writeUtil->get_node_coords( d, iter, end, count, buffer ); 00959 CHK_MB_ERR_1( rval, node_table, status ); 00960 } 00961 else 00962 memset( buffer, 0, count * sizeof( double ) ); 00963 00964 dbgOut.printf( 3, " writing %c node chunk %ld of %ld, %ld values at %ld\n", (char)( 'X' + d ), 00965 num_writes - remaining_writes + 1, num_writes, count, offset ); 00966 mhdf_writeNodeCoordWithOpt( node_table, offset, count, d, buffer, writeProp, &status ); 00967 CHK_MHDF_ERR_1( status, node_table ); 00968 } 00969 #else 00970 rval = writeUtil->get_node_coords( -1, iter, end, 3 * count, buffer ); 00971 CHK_MB_ERR_1( rval, node_table, status ); 00972 dbgOut.printf( 3, " writing node chunk %ld of %ld, %ld values at %ld\n", num_writes - remaining_writes + 1, 00973 num_writes, count, offset ); 00974 mhdf_writeNodeCoordsWithOpt( node_table, offset, count, buffer, writeProp, &status ); 00975 CHK_MHDF_ERR_1( status, node_table ); 00976 #endif 00977 track.record_io( offset, count ); 00978 00979 iter = end; 00980 offset += count; 00981 --remaining_writes; 00982 } 00983 00984 // Do empty writes if necessary for parallel collective IO 00985 if( collectiveIO ) 00986 { 00987 while( remaining_writes-- ) 00988 { 00989 assert( writeProp != H5P_DEFAULT ); 00990 #ifdef BLOCKED_COORD_IO 00991 for( int d = 0; d < dim; ++d ) 00992 { 00993 dbgOut.printf( 3, " writing (empty) %c node chunk %ld of %ld.\n", (char)( 'X' + d ), 00994 num_writes - remaining_writes, num_writes ); 00995 mhdf_writeNodeCoordWithOpt( node_table, offset, 0, d, 0, writeProp, &status ); 00996 CHK_MHDF_ERR_1( status, node_table ); 00997 } 00998 #else 00999 dbgOut.printf( 3, " writing (empty) node chunk %ld of %ld.\n", num_writes - remaining_writes, num_writes ); 01000 mhdf_writeNodeCoordsWithOpt( node_table, offset, 0, 0, writeProp, &status ); 01001 CHK_MHDF_ERR_1( status, node_table ); 01002 #endif 01003 } 01004 } 01005 01006 mhdf_closeData( filePtr, node_table, &status ); 01007 CHK_MHDF_ERR_0( status ); 01008 01009 track.all_reduce(); 01010 return MB_SUCCESS; 01011 } 01012 01013 ErrorCode WriteHDF5::write_elems( ExportSet& elems ) 01014 { 01015 mhdf_Status status; 01016 ErrorCode rval; 01017 long first_id; 01018 int nodes_per_elem; 01019 long table_size; 01020 01021 CHECK_OPEN_HANDLES; 01022 01023 debug_barrier(); 01024 dbgOut.printf( 2, "Writing %lu elements of type %s%d\n", (unsigned long)elems.range.size(), 01025 CN::EntityTypeName( elems.type ), elems.num_nodes ); 01026 dbgOut.print( 3, "Writing elements", elems.range ); 01027 01028 hid_t elem_table = mhdf_openConnectivity( filePtr, elems.name(), &nodes_per_elem, &table_size, &first_id, &status ); 01029 CHK_MHDF_ERR_0( status ); 01030 IODebugTrack track( debugTrack, elems.name() && strlen( elems.name() ) ? elems.name() : "<ANONYMOUS ELEM SET?>", 01031 table_size ); 01032 01033 assert( (unsigned long)first_id <= elems.first_id ); 01034 assert( (unsigned long)table_size >= elems.offset + elems.range.size() ); 01035 01036 EntityHandle* buffer = (EntityHandle*)dataBuffer; 01037 int chunk_size = bufferSize / ( elems.num_nodes * sizeof( wid_t ) ); 01038 long offset = elems.offset; 01039 long remaining = elems.range.size(); 01040 long num_writes = ( remaining + chunk_size - 1 ) / chunk_size; 01041 if( elems.max_num_ents ) 01042 { 01043 assert( elems.max_num_ents >= remaining ); 01044 num_writes = ( elems.max_num_ents + chunk_size - 1 ) / chunk_size; 01045 } 01046 long remaining_writes = num_writes; 01047 Range::iterator iter = elems.range.begin(); 01048 01049 while( remaining ) 01050 { 01051 (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 01052 long count = chunk_size < remaining ? chunk_size : remaining; 01053 remaining -= count; 01054 01055 Range::iterator next = iter; 01056 next += count; 01057 rval = writeUtil->get_element_connect( iter, next, elems.num_nodes, count * elems.num_nodes, buffer ); 01058 CHK_MB_ERR_1( rval, elem_table, status ); 01059 iter = next; 01060 01061 for( long i = 0; i < count * nodes_per_elem; ++i ) 01062 { 01063 buffer[i] = idMap.find( buffer[i] ); 01064 if( 0 == buffer[i] ) 01065 { 01066 MB_SET_ERR_CONT( "Invalid " << elems.name() << " element connectivity. Write Aborted" ); 01067 mhdf_closeData( filePtr, elem_table, &status ); 01068 return error( MB_FAILURE ); 01069 } 01070 } 01071 01072 dbgOut.printf( 3, " writing node connectivity %ld of %ld, %ld values at %ld\n", 01073 num_writes - remaining_writes + 1, num_writes, count, offset ); 01074 track.record_io( offset, count ); 01075 mhdf_writeConnectivityWithOpt( elem_table, offset, count, id_type, buffer, writeProp, &status ); 01076 CHK_MHDF_ERR_1( status, elem_table ); 01077 01078 offset += count; 01079 --remaining_writes; 01080 } 01081 01082 // Do empty writes if necessary for parallel collective IO 01083 if( collectiveIO ) 01084 { 01085 while( remaining_writes-- ) 01086 { 01087 assert( writeProp != H5P_DEFAULT ); 01088 dbgOut.printf( 3, " writing (empty) connectivity chunk %ld of %ld.\n", num_writes - remaining_writes + 1, 01089 num_writes ); 01090 mhdf_writeConnectivityWithOpt( elem_table, offset, 0, id_type, 0, writeProp, &status ); 01091 CHK_MHDF_ERR_1( status, elem_table ); 01092 } 01093 } 01094 01095 mhdf_closeData( filePtr, elem_table, &status ); 01096 CHK_MHDF_ERR_0( status ); 01097 01098 track.all_reduce(); 01099 return MB_SUCCESS; 01100 } 01101 01102 ErrorCode WriteHDF5::get_set_info( EntityHandle set, 01103 long& num_entities, 01104 long& num_children, 01105 long& num_parents, 01106 unsigned long& flags ) 01107 { 01108 ErrorCode rval; 01109 int i; 01110 unsigned int u; 01111 01112 rval = iFace->get_number_entities_by_handle( set, i, false ); 01113 CHK_MB_ERR_0( rval ); 01114 num_entities = i; 01115 01116 rval = iFace->num_child_meshsets( set, &i ); 01117 CHK_MB_ERR_0( rval ); 01118 num_children = i; 01119 01120 rval = iFace->num_parent_meshsets( set, &i ); 01121 CHK_MB_ERR_0( rval ); 01122 num_parents = i; 01123 01124 rval = iFace->get_meshset_options( set, u ); 01125 CHK_MB_ERR_0( rval ); 01126 flags = u; 01127 01128 return MB_SUCCESS; 01129 } 01130 01131 ErrorCode WriteHDF5::write_set_data( const WriteUtilIface::EntityListType which_data, 01132 const hid_t handle, 01133 IODebugTrack& track, 01134 Range* ranged, 01135 Range* null_stripped, 01136 std::vector< long >* set_sizes ) 01137 { 01138 // ranged must be non-null for CONTENTS and null for anything else 01139 assert( ( which_data == WriteUtilIface::CONTENTS ) == ( 0 != ranged ) ); 01140 ErrorCode rval; 01141 mhdf_Status status; 01142 01143 debug_barrier(); 01144 01145 // Function pointer type used to write set data 01146 void ( *write_func )( hid_t, long, long, hid_t, const void*, hid_t, mhdf_Status* ); 01147 long max_vals; // Max over all procs of number of values to write to data set 01148 long offset; // Offset in HDF5 dataset at which to write next block of data 01149 switch( which_data ) 01150 { 01151 case WriteUtilIface::CONTENTS: 01152 assert( ranged != 0 && null_stripped != 0 && set_sizes != 0 ); 01153 write_func = &mhdf_writeSetDataWithOpt; 01154 max_vals = maxNumSetContents; 01155 offset = setContentsOffset; 01156 dbgOut.print( 2, "Writing set contents\n" ); 01157 break; 01158 case WriteUtilIface::CHILDREN: 01159 assert( !ranged && !null_stripped && !set_sizes ); 01160 write_func = &mhdf_writeSetParentsChildrenWithOpt; 01161 max_vals = maxNumSetChildren; 01162 offset = setChildrenOffset; 01163 dbgOut.print( 2, "Writing set child lists\n" ); 01164 break; 01165 case WriteUtilIface::PARENTS: 01166 assert( !ranged && !null_stripped && !set_sizes ); 01167 write_func = &mhdf_writeSetParentsChildrenWithOpt; 01168 max_vals = maxNumSetParents; 01169 offset = setParentsOffset; 01170 dbgOut.print( 2, "Writing set parent lists\n" ); 01171 break; 01172 default: 01173 assert( false ); 01174 return MB_FAILURE; 01175 } 01176 // assert(max_vals > 0); // Should have skipped this function otherwise 01177 01178 // buffer to use for IO 01179 wid_t* buffer = reinterpret_cast< wid_t* >( dataBuffer ); 01180 // number of handles that will fit in the buffer 01181 const size_t buffer_size = bufferSize / sizeof( EntityHandle ); 01182 // the total number of write calls that must be made, including no-ops for collective io 01183 const size_t num_total_writes = ( max_vals + buffer_size - 1 ) / buffer_size; 01184 01185 std::vector< SpecialSetData >::iterator si = specialSets.begin(); 01186 01187 std::vector< wid_t > remaining; // data left over from prev iteration because it didn't fit in buffer 01188 size_t remaining_offset = 0; // avoid erasing from front of 'remaining' 01189 const EntityHandle* remaining_ptr = 0; // remaining for non-ranged data 01190 size_t remaining_count = 0; 01191 const wid_t* special_rem_ptr = 0; 01192 Range::const_iterator i = setSet.range.begin(), j, rhint, nshint; 01193 if( ranged ) rhint = ranged->begin(); 01194 if( null_stripped ) nshint = null_stripped->begin(); 01195 for( size_t w = 0; w < num_total_writes; ++w ) 01196 { 01197 if( i == setSet.range.end() && !remaining.empty() && !remaining_ptr ) 01198 { 01199 // If here, then we've written everything but we need to 01200 // make more write calls because we're doing collective IO 01201 // in parallel 01202 ( *write_func )( handle, 0, 0, id_type, 0, writeProp, &status ); 01203 CHK_MHDF_ERR_0( status ); 01204 continue; 01205 } 01206 01207 // If we had some left-over data from a range-compacted set 01208 // from the last iteration, add it to the buffer now 01209 size_t count = 0; 01210 if( !remaining.empty() ) 01211 { 01212 count = remaining.size() - remaining_offset; 01213 if( count > buffer_size ) 01214 { 01215 memcpy( buffer, &remaining[remaining_offset], buffer_size * sizeof( wid_t ) ); 01216 count = buffer_size; 01217 remaining_offset += buffer_size; 01218 } 01219 else 01220 { 01221 memcpy( buffer, &remaining[remaining_offset], count * sizeof( wid_t ) ); 01222 remaining_offset = 0; 01223 remaining.clear(); 01224 } 01225 } 01226 // If we had some left-over data from a non-range-compacted set 01227 // from the last iteration, add it to the buffer now 01228 else if( remaining_ptr ) 01229 { 01230 if( remaining_count > buffer_size ) 01231 { 01232 rval = vector_to_id_list( remaining_ptr, buffer, buffer_size ); 01233 CHK_MB_ERR_0( rval ); 01234 count = buffer_size; 01235 remaining_ptr += count; 01236 remaining_count -= count; 01237 } 01238 else 01239 { 01240 rval = vector_to_id_list( remaining_ptr, buffer, remaining_count ); 01241 CHK_MB_ERR_0( rval ); 01242 count = remaining_count; 01243 remaining_ptr = 0; 01244 remaining_count = 0; 01245 } 01246 } 01247 // If we had some left-over data from a "special" (i.e. parallel shared) 01248 // set. 01249 else if( special_rem_ptr ) 01250 { 01251 if( remaining_count > buffer_size ) 01252 { 01253 memcpy( buffer, special_rem_ptr, buffer_size * sizeof( wid_t ) ); 01254 count = buffer_size; 01255 special_rem_ptr += count; 01256 remaining_count -= count; 01257 } 01258 else 01259 { 01260 memcpy( buffer, special_rem_ptr, remaining_count * sizeof( wid_t ) ); 01261 count = remaining_count; 01262 special_rem_ptr = 0; 01263 remaining_count = 0; 01264 } 01265 } 01266 01267 // While there is both space remaining in the buffer and 01268 // more sets to write, append more set data to buffer. 01269 01270 while( count < buffer_size && i != setSet.range.end() ) 01271 { 01272 // Special case for "special" (i.e. parallel shared) sets: 01273 // we already have the data in a vector, just copy it. 01274 if( si != specialSets.end() && si->setHandle == *i ) 01275 { 01276 std::vector< wid_t >& list = ( which_data == WriteUtilIface::CONTENTS ) ? si->contentIds 01277 : ( which_data == WriteUtilIface::PARENTS ) ? si->parentIds 01278 : si->childIds; 01279 size_t append = list.size(); 01280 if( count + list.size() > buffer_size ) 01281 { 01282 append = buffer_size - count; 01283 special_rem_ptr = &list[append]; 01284 remaining_count = list.size() - append; 01285 } 01286 memcpy( buffer + count, &list[0], append * sizeof( wid_t ) ); 01287 ++i; 01288 ++si; 01289 count += append; 01290 continue; 01291 } 01292 01293 j = i; 01294 ++i; 01295 const EntityHandle* ptr; 01296 int len; 01297 unsigned char flags; 01298 rval = writeUtil->get_entity_list_pointers( j, i, &ptr, which_data, &len, &flags ); 01299 if( MB_SUCCESS != rval ) return rval; 01300 if( which_data == WriteUtilIface::CONTENTS && !( flags & MESHSET_ORDERED ) ) 01301 { 01302 bool compacted; 01303 remaining.clear(); 01304 if( len == 0 ) 01305 compacted = false; 01306 else 01307 { 01308 assert( !( len % 2 ) ); 01309 rval = range_to_blocked_list( ptr, len / 2, remaining, compacted ); 01310 if( MB_SUCCESS != rval ) return rval; 01311 } 01312 if( compacted ) 01313 { 01314 rhint = ranged->insert( rhint, *j ); 01315 set_sizes->push_back( remaining.size() ); 01316 } 01317 else if( remaining.size() != (unsigned)len ) 01318 { 01319 nshint = null_stripped->insert( nshint, *j ); 01320 set_sizes->push_back( remaining.size() ); 01321 } 01322 01323 if( count + remaining.size() <= buffer_size ) 01324 { 01325 if( !remaining.empty() ) 01326 memcpy( buffer + count, &remaining[0], sizeof( wid_t ) * remaining.size() ); 01327 count += remaining.size(); 01328 remaining.clear(); 01329 remaining_offset = 0; 01330 } 01331 else 01332 { 01333 remaining_offset = buffer_size - count; 01334 memcpy( buffer + count, &remaining[0], sizeof( wid_t ) * remaining_offset ); 01335 count += remaining_offset; 01336 } 01337 } 01338 else 01339 { 01340 if( count + len > buffer_size ) 01341 { 01342 size_t append = buffer_size - count; 01343 remaining_ptr = ptr + append; 01344 remaining_count = len - append; 01345 len = append; 01346 } 01347 01348 rval = vector_to_id_list( ptr, buffer + count, len ); 01349 count += len; 01350 } 01351 } 01352 01353 // Write the buffer. 01354 ( *write_func )( handle, offset, count, id_type, buffer, writeProp, &status ); 01355 CHK_MHDF_ERR_0( status ); 01356 track.record_io( offset, count ); 01357 offset += count; 01358 } 01359 01360 return MB_SUCCESS; 01361 } 01362 01363 ErrorCode WriteHDF5::write_sets( double* times ) 01364 { 01365 mhdf_Status status; 01366 ErrorCode rval; 01367 long first_id, size; 01368 hid_t table; 01369 CpuTimer timer; 01370 01371 CHECK_OPEN_HANDLES; 01372 /* If no sets, just return success */ 01373 if( !writeSets ) return MB_SUCCESS; 01374 01375 debug_barrier(); 01376 dbgOut.printf( 2, "Writing %lu non-shared sets\n", (unsigned long)setSet.range.size() ); 01377 dbgOut.print( 3, "Non-shared sets", setSet.range ); 01378 01379 /* Write set parents */ 01380 if( writeSetParents ) 01381 { 01382 topState.start( "writing parent lists for local sets" ); 01383 table = mhdf_openSetParents( filePtr, &size, &status ); 01384 CHK_MHDF_ERR_0( status ); 01385 IODebugTrack track( debugTrack, "SetParents", size ); 01386 01387 rval = write_set_data( WriteUtilIface::PARENTS, table, track ); 01388 topState.end( rval ); 01389 CHK_MB_ERR_1( rval, table, status ); 01390 01391 mhdf_closeData( filePtr, table, &status ); 01392 CHK_MHDF_ERR_0( status ); 01393 01394 times[SET_PARENT] = timer.time_elapsed(); 01395 track.all_reduce(); 01396 } 01397 01398 /* Write set children */ 01399 if( writeSetChildren ) 01400 { 01401 topState.start( "writing child lists for local sets" ); 01402 table = mhdf_openSetChildren( filePtr, &size, &status ); 01403 CHK_MHDF_ERR_0( status ); 01404 IODebugTrack track( debugTrack, "SetChildren", size ); 01405 01406 rval = write_set_data( WriteUtilIface::CHILDREN, table, track ); 01407 topState.end( rval ); 01408 CHK_MB_ERR_1( rval, table, status ); 01409 01410 mhdf_closeData( filePtr, table, &status ); 01411 CHK_MHDF_ERR_0( status ); 01412 01413 times[SET_CHILD] = timer.time_elapsed(); 01414 track.all_reduce(); 01415 } 01416 01417 /* Write set contents */ 01418 Range ranged_sets, null_stripped_sets; 01419 std::vector< long > set_sizes; 01420 if( writeSetContents ) 01421 { 01422 topState.start( "writing content lists for local sets" ); 01423 table = mhdf_openSetData( filePtr, &size, &status ); 01424 CHK_MHDF_ERR_0( status ); 01425 IODebugTrack track( debugTrack, "SetContents", size ); 01426 01427 rval = write_set_data( WriteUtilIface::CONTENTS, table, track, &ranged_sets, &null_stripped_sets, &set_sizes ); 01428 topState.end( rval ); 01429 CHK_MB_ERR_1( rval, table, status ); 01430 01431 mhdf_closeData( filePtr, table, &status ); 01432 CHK_MHDF_ERR_0( status ); 01433 01434 times[SET_CONTENT] = timer.time_elapsed(); 01435 track.all_reduce(); 01436 } 01437 assert( ranged_sets.size() + null_stripped_sets.size() == set_sizes.size() ); 01438 01439 /* Write set description table */ 01440 01441 debug_barrier(); 01442 topState.start( "writing descriptions of local sets" ); 01443 dbgOut.printf( 2, "Writing %lu non-shared sets\n", (unsigned long)setSet.range.size() ); 01444 dbgOut.print( 3, "Non-shared sets", setSet.range ); 01445 01446 /* Open the table */ 01447 table = mhdf_openSetMeta( filePtr, &size, &first_id, &status ); 01448 CHK_MHDF_ERR_0( status ); 01449 IODebugTrack track_meta( debugTrack, "SetMeta", size ); 01450 01451 /* Some debug stuff */ 01452 debug_barrier(); 01453 dbgOut.printf( 2, "Writing %lu non-shared sets\n", (unsigned long)setSet.range.size() ); 01454 dbgOut.print( 3, "Non-shared sets", setSet.range ); 01455 01456 /* Counts and buffers and such */ 01457 mhdf_index_t* const buffer = reinterpret_cast< mhdf_index_t* >( dataBuffer ); 01458 const size_t buffer_size = bufferSize / ( 4 * sizeof( mhdf_index_t ) ); 01459 const size_t num_local_writes = ( setSet.range.size() + buffer_size - 1 ) / buffer_size; 01460 const size_t num_global_writes = ( setSet.max_num_ents + buffer_size - 1 ) / buffer_size; 01461 assert( num_local_writes <= num_global_writes ); 01462 assert( num_global_writes > 0 ); 01463 01464 /* data about sets for which number of handles written is 01465 * not the same as the number of handles in the set 01466 * (range-compacted or null handles stripped out) 01467 */ 01468 Range::const_iterator i = setSet.range.begin(); 01469 Range::const_iterator r = ranged_sets.begin(); 01470 Range::const_iterator s = null_stripped_sets.begin(); 01471 std::vector< mhdf_index_t >::const_iterator n = set_sizes.begin(); 01472 assert( ranged_sets.size() + null_stripped_sets.size() == set_sizes.size() ); 01473 01474 /* We write the end index for each list, rather than the count */ 01475 mhdf_index_t prev_contents_end = setContentsOffset - 1; 01476 mhdf_index_t prev_children_end = setChildrenOffset - 1; 01477 mhdf_index_t prev_parents_end = setParentsOffset - 1; 01478 01479 /* While there is more data to write */ 01480 size_t offset = setSet.offset; 01481 std::vector< SpecialSetData >::const_iterator si = specialSets.begin(); 01482 for( size_t w = 0; w < num_local_writes; ++w ) 01483 { 01484 // Get a buffer full of data 01485 size_t count = 0; 01486 while( count < buffer_size && i != setSet.range.end() ) 01487 { 01488 // Get set properties 01489 long num_ent, num_child, num_parent; 01490 unsigned long flags; 01491 if( si != specialSets.end() && si->setHandle == *i ) 01492 { 01493 flags = si->setFlags; 01494 num_ent = si->contentIds.size(); 01495 num_child = si->childIds.size(); 01496 num_parent = si->parentIds.size(); 01497 ++si; 01498 if( r != ranged_sets.end() && *i == *r ) 01499 { 01500 assert( flags & mhdf_SET_RANGE_BIT ); 01501 ++r; 01502 ++n; 01503 } 01504 else if( s != null_stripped_sets.end() && *i == *s ) 01505 { 01506 ++s; 01507 ++n; 01508 } 01509 } 01510 else 01511 { 01512 assert( si == specialSets.end() || si->setHandle > *i ); 01513 01514 // Get set properties 01515 rval = get_set_info( *i, num_ent, num_child, num_parent, flags ); 01516 CHK_MB_ERR_1( rval, table, status ); 01517 01518 // Check if size is something other than num handles in set 01519 if( r != ranged_sets.end() && *i == *r ) 01520 { 01521 num_ent = *n; 01522 ++r; 01523 ++n; 01524 flags |= mhdf_SET_RANGE_BIT; 01525 } 01526 else if( s != null_stripped_sets.end() && *i == *s ) 01527 { 01528 num_ent = *n; 01529 ++s; 01530 ++n; 01531 } 01532 } 01533 01534 // Put data in buffer 01535 mhdf_index_t* local = buffer + 4 * count; 01536 prev_contents_end += num_ent; 01537 prev_children_end += num_child; 01538 prev_parents_end += num_parent; 01539 local[0] = prev_contents_end; 01540 local[1] = prev_children_end; 01541 local[2] = prev_parents_end; 01542 local[3] = flags; 01543 01544 // Iterate 01545 ++count; 01546 ++i; 01547 } 01548 01549 // Write the data 01550 mhdf_writeSetMetaWithOpt( table, offset, count, MHDF_INDEX_TYPE, buffer, writeProp, &status ); 01551 CHK_MHDF_ERR_1( status, table ); 01552 track_meta.record_io( offset, count ); 01553 offset += count; 01554 } 01555 assert( r == ranged_sets.end() ); 01556 assert( s == null_stripped_sets.end() ); 01557 assert( n == set_sizes.end() ); 01558 01559 /* If doing parallel write with collective IO, do null write 01560 * calls because other procs aren't done yet and write calls 01561 * are collective */ 01562 for( size_t w = num_local_writes; w != num_global_writes; ++w ) 01563 { 01564 mhdf_writeSetMetaWithOpt( table, 0, 0, MHDF_INDEX_TYPE, 0, writeProp, &status ); 01565 CHK_MHDF_ERR_1( status, table ); 01566 } 01567 01568 topState.end(); 01569 mhdf_closeData( filePtr, table, &status ); 01570 CHK_MHDF_ERR_0( status ); 01571 01572 times[SET_META] = timer.time_elapsed(); 01573 track_meta.all_reduce(); 01574 01575 return MB_SUCCESS; 01576 } 01577 01578 template < class HandleRangeIter > 01579 inline size_t count_num_handles( HandleRangeIter iter, HandleRangeIter end ) 01580 { 01581 size_t result = 0; 01582 for( ; iter != end; ++iter ) 01583 result += iter->second - iter->first + 1; 01584 01585 return result; 01586 } 01587 01588 template < class HandleRangeIter > 01589 inline ErrorCode range_to_id_list_templ( HandleRangeIter begin, 01590 HandleRangeIter end, 01591 const RangeMap< EntityHandle, WriteHDF5::wid_t >& idMap, 01592 WriteHDF5::wid_t* array ) 01593 { 01594 ErrorCode rval = MB_SUCCESS; 01595 RangeMap< EntityHandle, WriteHDF5::wid_t >::iterator ri = idMap.begin(); 01596 WriteHDF5::wid_t* i = array; 01597 for( HandleRangeIter pi = begin; pi != end; ++pi ) 01598 { 01599 EntityHandle h = pi->first; 01600 while( h <= pi->second ) 01601 { 01602 ri = idMap.lower_bound( ri, idMap.end(), h ); 01603 if( ri == idMap.end() || ri->begin > h ) 01604 { 01605 rval = MB_ENTITY_NOT_FOUND; 01606 *i = 0; 01607 ++i; 01608 ++h; 01609 continue; 01610 } 01611 01612 // compute the last available value of the found target range (ri iterator) 01613 WriteHDF5::wid_t last_valid_input_value_in_current_map_range = ri->begin + ri->count - 1; 01614 // limit the number of steps we do on top of h so we do not overflow the output range 01615 // span 01616 WriteHDF5::wid_t step_until = std::min( last_valid_input_value_in_current_map_range, pi->second ); 01617 WriteHDF5::wid_t n = step_until - h + 1; 01618 assert( n > 0 ); // We must at least step 1 01619 01620 WriteHDF5::wid_t id = ri->value + ( h - ri->begin ); 01621 for( WriteHDF5::wid_t j = 0; j < n; ++i, ++j ) 01622 *i = id + j; 01623 h += n; 01624 } 01625 } 01626 01627 assert( i == array + count_num_handles( begin, end ) ); 01628 return rval; 01629 } 01630 01631 template < class HandleRangeIter > 01632 inline ErrorCode range_to_blocked_list_templ( HandleRangeIter begin, 01633 HandleRangeIter end, 01634 const RangeMap< EntityHandle, WriteHDF5::wid_t >& idMap, 01635 std::vector< WriteHDF5::wid_t >& output_id_list, 01636 bool& ranged_list ) 01637 { 01638 output_id_list.clear(); 01639 if( begin == end ) 01640 { 01641 ranged_list = false; 01642 return MB_SUCCESS; 01643 } 01644 01645 // First try ranged format, but give up if we reach the 01646 // non-range format size. 01647 RangeMap< EntityHandle, WriteHDF5::wid_t >::iterator ri = idMap.begin(); 01648 01649 const size_t num_handles = count_num_handles( begin, end ); 01650 // If we end up with more than this many range blocks, then 01651 // we're better off just writing the set as a simple list 01652 size_t pairs_remaining = num_handles / 2; 01653 for( HandleRangeIter pi = begin; pi != end; ++pi ) 01654 { 01655 EntityHandle h = pi->first; 01656 WriteHDF5::wid_t local_mapped_from_subrange = 0; 01657 while( h <= pi->second ) 01658 { 01659 ri = idMap.lower_bound( ri, idMap.end(), h ); 01660 if( ri == idMap.end() || ri->begin > h ) 01661 { 01662 ++h; 01663 continue; 01664 } 01665 01666 WriteHDF5::wid_t n = pi->second - pi->first + 1 - local_mapped_from_subrange; 01667 if( n > ri->count ) n = ri->count; 01668 01669 WriteHDF5::wid_t id = ri->value + ( h - ri->begin ); 01670 // see if we can go to the end of the range 01671 if( id + n > ri->value + ri->count ) // we have to reduce n, because we cannot go over next subrange 01672 { 01673 if( ri->value + ri->count - id > 0 ) n = ri->value + ri->count - id; 01674 } 01675 01676 // See if we can append it to the previous range 01677 if( !output_id_list.empty() && output_id_list[output_id_list.size() - 2] + output_id_list.back() == id ) 01678 { 01679 output_id_list.back() += n; 01680 } 01681 01682 // If we ran out of space, (or set is empty) just do list format 01683 else if( !pairs_remaining ) 01684 { 01685 ranged_list = false; 01686 output_id_list.resize( num_handles ); 01687 range_to_id_list_templ( begin, end, idMap, &output_id_list[0] ); 01688 output_id_list.erase( std::remove( output_id_list.begin(), output_id_list.end(), 0u ), 01689 output_id_list.end() ); 01690 return MB_SUCCESS; 01691 } 01692 01693 // 01694 else 01695 { 01696 --pairs_remaining; 01697 output_id_list.push_back( id ); 01698 output_id_list.push_back( n ); 01699 } 01700 local_mapped_from_subrange += n; // we already mapped so many 01701 h += n; 01702 } 01703 } 01704 01705 ranged_list = true; 01706 return MB_SUCCESS; 01707 } 01708 01709 ErrorCode WriteHDF5::range_to_blocked_list( const Range& input_range, 01710 std::vector< wid_t >& output_id_list, 01711 bool& ranged_list ) 01712 { 01713 return range_to_blocked_list_templ( input_range.const_pair_begin(), input_range.const_pair_end(), idMap, 01714 output_id_list, ranged_list ); 01715 } 01716 01717 ErrorCode WriteHDF5::range_to_blocked_list( const EntityHandle* array, 01718 size_t num_input_ranges, 01719 std::vector< wid_t >& output_id_list, 01720 bool& ranged_list ) 01721 { 01722 // We assume this in the cast on the following line 01723 typedef std::pair< EntityHandle, EntityHandle > mtype; 01724 assert( sizeof( mtype ) == 2 * sizeof( EntityHandle ) ); 01725 const mtype* arr = reinterpret_cast< const mtype* >( array ); 01726 return range_to_blocked_list_templ( arr, arr + num_input_ranges, idMap, output_id_list, ranged_list ); 01727 } 01728 01729 ErrorCode WriteHDF5::range_to_id_list( const Range& range, wid_t* array ) 01730 { 01731 return range_to_id_list_templ( range.const_pair_begin(), range.const_pair_end(), idMap, array ); 01732 } 01733 01734 ErrorCode WriteHDF5::vector_to_id_list( const EntityHandle* input, 01735 size_t input_len, 01736 wid_t* output, 01737 size_t& output_len, 01738 bool remove_zeros ) 01739 { 01740 const EntityHandle* i_iter = input; 01741 const EntityHandle* i_end = input + input_len; 01742 wid_t* o_iter = output; 01743 for( ; i_iter != i_end; ++i_iter ) 01744 { 01745 wid_t id = idMap.find( *i_iter ); 01746 if( !remove_zeros || id != 0 ) 01747 { 01748 *o_iter = id; 01749 ++o_iter; 01750 } 01751 } 01752 output_len = o_iter - output; 01753 01754 return MB_SUCCESS; 01755 } 01756 01757 ErrorCode WriteHDF5::vector_to_id_list( const std::vector< EntityHandle >& input, 01758 std::vector< wid_t >& output, 01759 bool remove_zeros ) 01760 { 01761 output.resize( input.size() ); 01762 size_t output_size = 0; 01763 ErrorCode rval = vector_to_id_list( &input[0], input.size(), &output[0], output_size, remove_zeros ); 01764 output.resize( output_size ); 01765 return rval; 01766 } 01767 01768 ErrorCode WriteHDF5::vector_to_id_list( const EntityHandle* input, wid_t* output, size_t count ) 01769 { 01770 size_t output_len; 01771 return vector_to_id_list( input, count, output, output_len, false ); 01772 } 01773 01774 inline ErrorCode WriteHDF5::get_adjacencies( EntityHandle entity, std::vector< wid_t >& adj ) 01775 { 01776 const EntityHandle* adj_array; 01777 int num_adj; 01778 ErrorCode rval = writeUtil->get_adjacencies( entity, adj_array, num_adj ); 01779 if( MB_SUCCESS != rval ) return error( rval ); 01780 01781 size_t j = 0; 01782 adj.resize( num_adj ); 01783 for( int i = 0; i < num_adj; ++i ) 01784 if( wid_t id = idMap.find( adj_array[i] ) ) adj[j++] = id; 01785 adj.resize( j ); 01786 01787 return MB_SUCCESS; 01788 } 01789 01790 ErrorCode WriteHDF5::write_adjacencies( const ExportSet& elements ) 01791 { 01792 ErrorCode rval; 01793 mhdf_Status status; 01794 Range::const_iterator iter; 01795 const Range::const_iterator end = elements.range.end(); 01796 std::vector< wid_t > adj_list; 01797 01798 CHECK_OPEN_HANDLES; 01799 01800 debug_barrier(); 01801 01802 /* Count Adjacencies */ 01803 long count = 0; 01804 // for (iter = elements.range.begin(); iter != end; ++iter) { 01805 // adj_list.clear(); 01806 // rval = get_adjacencies(*iter, adj_list);CHK_MB_ERR_0(rval); 01807 // 01808 // if (adj_list.size() > 0) 01809 // count += adj_list.size() + 2; 01810 //} 01811 01812 // if (count == 0) 01813 // return MB_SUCCESS; 01814 01815 long offset = elements.adj_offset; 01816 if( elements.max_num_adjs == 0 ) return MB_SUCCESS; 01817 01818 /* Create data list */ 01819 hid_t table = mhdf_openAdjacency( filePtr, elements.name(), &count, &status ); 01820 CHK_MHDF_ERR_0( status ); 01821 IODebugTrack track( debugTrack, "Adjacencies", count ); 01822 01823 /* Write data */ 01824 wid_t* buffer = (wid_t*)dataBuffer; 01825 long chunk_size = bufferSize / sizeof( wid_t ); 01826 long num_writes = ( elements.max_num_adjs + chunk_size - 1 ) / chunk_size; 01827 (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 01828 count = 0; 01829 for( iter = elements.range.begin(); iter != end; ++iter ) 01830 { 01831 adj_list.clear(); 01832 rval = get_adjacencies( *iter, adj_list ); 01833 CHK_MB_ERR_1( rval, table, status ); 01834 if( adj_list.size() == 0 ) continue; 01835 01836 // If buffer is full, flush it 01837 if( count + adj_list.size() + 2 > (unsigned long)chunk_size ) 01838 { 01839 dbgOut.print( 3, " writing adjacency chunk.\n" ); 01840 track.record_io( offset, count ); 01841 mhdf_writeAdjacencyWithOpt( table, offset, count, id_type, buffer, writeProp, &status ); 01842 CHK_MHDF_ERR_1( status, table ); 01843 (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 01844 01845 offset += count; 01846 count = 0; 01847 } 01848 01849 buffer[count++] = idMap.find( *iter ); 01850 buffer[count++] = adj_list.size(); 01851 01852 assert( adj_list.size() + 2 < (unsigned long)chunk_size ); 01853 memcpy( buffer + count, &adj_list[0], adj_list.size() * sizeof( wid_t ) ); 01854 count += adj_list.size(); 01855 } 01856 01857 if( count ) 01858 { 01859 dbgOut.print( 2, " writing final adjacency chunk.\n" ); 01860 mhdf_writeAdjacencyWithOpt( table, offset, count, id_type, buffer, writeProp, &status ); 01861 CHK_MHDF_ERR_1( status, table ); 01862 01863 offset += count; 01864 count = 0; 01865 --num_writes; 01866 } 01867 01868 // Do empty writes if necessary for parallel collective IO 01869 if( collectiveIO ) 01870 { 01871 while( num_writes > 0 ) 01872 { 01873 --num_writes; 01874 assert( writeProp != H5P_DEFAULT ); 01875 dbgOut.print( 2, " writing empty adjacency chunk.\n" ); 01876 mhdf_writeAdjacencyWithOpt( table, offset, 0, id_type, 0, writeProp, &status ); 01877 CHK_MHDF_ERR_1( status, table ); 01878 } 01879 } 01880 01881 mhdf_closeData( filePtr, table, &status ); 01882 CHK_MHDF_ERR_0( status ); 01883 01884 track.all_reduce(); 01885 return MB_SUCCESS; 01886 } 01887 01888 ErrorCode WriteHDF5::write_tag( const TagDesc& tag_data, double* times ) 01889 { 01890 std::string name; 01891 ErrorCode rval = iFace->tag_get_name( tag_data.tag_id, name ); 01892 if( MB_SUCCESS != rval ) return error( rval ); 01893 01894 CHECK_OPEN_HANDLES; 01895 debug_barrier(); 01896 dbgOut.tprintf( 1, "Writing tag: \"%s\"\n", name.c_str() ); 01897 01898 int moab_size, elem_size, array_len; 01899 DataType moab_type; 01900 mhdf_TagDataType mhdf_type; 01901 hid_t hdf5_type; 01902 rval = get_tag_size( tag_data.tag_id, moab_type, moab_size, elem_size, array_len, mhdf_type, hdf5_type ); 01903 if( MB_SUCCESS != rval ) return error( rval ); 01904 01905 CpuTimer timer; 01906 if( array_len == MB_VARIABLE_LENGTH && tag_data.write_sparse ) 01907 { 01908 dbgOut.printf( 2, "Writing sparse data for var-len tag: \"%s\"\n", name.c_str() ); 01909 rval = write_var_len_tag( tag_data, name, moab_type, hdf5_type, elem_size ); 01910 times[VARLEN_TAG_TIME] += timer.time_elapsed(); 01911 } 01912 else 01913 { 01914 int data_len = elem_size; 01915 if( moab_type != MB_TYPE_BIT ) data_len *= array_len; 01916 if( tag_data.write_sparse ) 01917 { 01918 dbgOut.printf( 2, "Writing sparse data for tag: \"%s\"\n", name.c_str() ); 01919 rval = write_sparse_tag( tag_data, name, moab_type, hdf5_type, data_len ); 01920 times[SPARSE_TAG_TIME] += timer.time_elapsed(); 01921 } 01922 for( size_t i = 0; MB_SUCCESS == rval && i < tag_data.dense_list.size(); ++i ) 01923 { 01924 const ExportSet* set = find( tag_data.dense_list[i] ); 01925 assert( 0 != set ); 01926 debug_barrier(); 01927 dbgOut.printf( 2, "Writing dense data for tag: \"%s\" on group \"%s\"\n", name.c_str(), set->name() ); 01928 subState.start( "writing dense data for tag: ", ( name + ":" + set->name() ).c_str() ); 01929 rval = write_dense_tag( tag_data, *set, name, moab_type, hdf5_type, data_len ); 01930 subState.end( rval ); 01931 } 01932 times[DENSE_TAG_TIME] += timer.time_elapsed(); 01933 } 01934 01935 H5Tclose( hdf5_type ); 01936 return MB_SUCCESS == rval ? MB_SUCCESS : error( rval ); 01937 } 01938 01939 ErrorCode WriteHDF5::write_sparse_ids( const TagDesc& tag_data, 01940 const Range& range, 01941 hid_t id_table, 01942 size_t table_size, 01943 const char* name ) 01944 { 01945 ErrorCode rval; 01946 mhdf_Status status; 01947 01948 CHECK_OPEN_HANDLES; 01949 01950 std::string tname( name ? name : "<UNKNOWN TAG?>" ); 01951 tname += " - Ids"; 01952 IODebugTrack track( debugTrack, tname, table_size ); 01953 01954 // Set up data buffer for writing IDs 01955 size_t chunk_size = bufferSize / sizeof( wid_t ); 01956 wid_t* id_buffer = (wid_t*)dataBuffer; 01957 01958 // Write IDs of tagged entities. 01959 long remaining = range.size(); 01960 long offset = tag_data.sparse_offset; 01961 long num_writes = ( remaining + chunk_size - 1 ) / chunk_size; 01962 if( tag_data.max_num_ents ) 01963 { 01964 assert( tag_data.max_num_ents >= (unsigned long)remaining ); 01965 num_writes = ( tag_data.max_num_ents + chunk_size - 1 ) / chunk_size; 01966 } 01967 Range::const_iterator iter = range.begin(); 01968 while( remaining ) 01969 { 01970 (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 01971 01972 // Write "chunk_size" blocks of data 01973 long count = (unsigned long)remaining > chunk_size ? chunk_size : remaining; 01974 remaining -= count; 01975 Range::const_iterator stop = iter; 01976 stop += count; 01977 Range tmp; 01978 ; 01979 tmp.merge( iter, stop ); 01980 iter = stop; 01981 assert( tmp.size() == (unsigned)count ); 01982 01983 rval = range_to_id_list( tmp, id_buffer ); 01984 CHK_MB_ERR_0( rval ); 01985 01986 // Write the data 01987 dbgOut.print( 3, " writing sparse tag entity chunk.\n" ); 01988 track.record_io( offset, count ); 01989 mhdf_writeSparseTagEntitiesWithOpt( id_table, offset, count, id_type, id_buffer, writeProp, &status ); 01990 CHK_MHDF_ERR_0( status ); 01991 01992 offset += count; 01993 --num_writes; 01994 } // while (remaining) 01995 01996 // Do empty writes if necessary for parallel collective IO 01997 if( collectiveIO ) 01998 { 01999 while( num_writes-- ) 02000 { 02001 assert( writeProp != H5P_DEFAULT ); 02002 dbgOut.print( 3, " writing empty sparse tag entity chunk.\n" ); 02003 mhdf_writeSparseTagEntitiesWithOpt( id_table, offset, 0, id_type, 0, writeProp, &status ); 02004 CHK_MHDF_ERR_0( status ); 02005 } 02006 } 02007 02008 track.all_reduce(); 02009 return MB_SUCCESS; 02010 } 02011 02012 ErrorCode WriteHDF5::write_sparse_tag( const TagDesc& tag_data, 02013 const std::string& name, 02014 DataType mb_data_type, 02015 hid_t value_type, 02016 int value_type_size ) 02017 { 02018 ErrorCode rval; 02019 mhdf_Status status; 02020 hid_t tables[3]; 02021 long table_size, data_size; 02022 02023 CHECK_OPEN_HANDLES; 02024 02025 // Get entities for which to write tag values 02026 Range range; 02027 rval = get_sparse_tagged_entities( tag_data, range ); 02028 02029 // Open tables to write info 02030 mhdf_openSparseTagData( filePtr, name.c_str(), &table_size, &data_size, tables, &status ); 02031 CHK_MHDF_ERR_0( status ); 02032 assert( range.size() + tag_data.sparse_offset <= (unsigned long)table_size ); 02033 // Fixed-length tag 02034 assert( table_size == data_size ); 02035 02036 // Write IDs for tagged entities 02037 subState.start( "writing sparse ids for tag: ", name.c_str() ); 02038 rval = write_sparse_ids( tag_data, range, tables[0], table_size, name.c_str() ); 02039 subState.end( rval ); 02040 CHK_MB_ERR_2( rval, tables, status ); 02041 mhdf_closeData( filePtr, tables[0], &status ); 02042 CHK_MHDF_ERR_1( status, tables[1] ); 02043 02044 // Set up data buffer for writing tag values 02045 IODebugTrack track( debugTrack, name + " Data", data_size ); 02046 subState.start( "writing sparse values for tag: ", name.c_str() ); 02047 rval = write_tag_values( tag_data.tag_id, tables[1], tag_data.sparse_offset, range, mb_data_type, value_type, 02048 value_type_size, tag_data.max_num_ents, track ); 02049 subState.end( rval ); 02050 CHK_MB_ERR_0( rval ); 02051 mhdf_closeData( filePtr, tables[1], &status ); 02052 CHK_MHDF_ERR_0( status ); 02053 02054 track.all_reduce(); 02055 return MB_SUCCESS; 02056 } 02057 02058 ErrorCode WriteHDF5::write_var_len_indices( const TagDesc& tag_data, 02059 const Range& range, 02060 hid_t idx_table, 02061 size_t table_size, 02062 int /*type_size*/, 02063 const char* name ) 02064 { 02065 ErrorCode rval; 02066 mhdf_Status status; 02067 02068 CHECK_OPEN_HANDLES; 02069 02070 std::string tname( name ? name : "<UNKNOWN TAG?>" ); 02071 tname += " - End Indices"; 02072 IODebugTrack track( debugTrack, tname, table_size ); 02073 02074 // Set up data buffer for writing indices 02075 size_t chunk_size = bufferSize / ( std::max( sizeof( void* ), sizeof( long ) ) + sizeof( int ) ); 02076 mhdf_index_t* idx_buffer = (mhdf_index_t*)dataBuffer; 02077 const void** junk = (const void**)dataBuffer; 02078 int* size_buffer = (int*)( dataBuffer + chunk_size * std::max( sizeof( void* ), sizeof( mhdf_index_t ) ) ); 02079 02080 // Write IDs of tagged entities. 02081 long data_offset = tag_data.var_data_offset - 1; // Offset at which to write data buffer 02082 size_t remaining = range.size(); 02083 size_t offset = tag_data.sparse_offset; 02084 size_t num_writes = ( remaining + chunk_size - 1 ) / chunk_size; 02085 if( tag_data.max_num_ents ) 02086 { 02087 assert( tag_data.max_num_ents >= (unsigned long)remaining ); 02088 num_writes = ( tag_data.max_num_ents + chunk_size - 1 ) / chunk_size; 02089 } 02090 Range::const_iterator iter = range.begin(); 02091 while( remaining ) 02092 { 02093 (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 02094 02095 // Write "chunk_size" blocks of data 02096 size_t count = remaining > chunk_size ? chunk_size : remaining; 02097 remaining -= count; 02098 Range::const_iterator stop = iter; 02099 stop += count; 02100 Range tmp; 02101 tmp.merge( iter, stop ); 02102 iter = stop; 02103 assert( tmp.size() == (unsigned)count ); 02104 02105 rval = iFace->tag_get_by_ptr( tag_data.tag_id, tmp, junk, size_buffer ); 02106 CHK_MB_ERR_0( rval ); 02107 02108 // Calculate end indices 02109 dbgOut.print( 3, " writing var-len tag offset chunk.\n" ); 02110 track.record_io( offset, count ); 02111 for( size_t i = 0; i < count; ++i ) 02112 { 02113 data_offset += size_buffer[i]; 02114 idx_buffer[i] = data_offset; 02115 } 02116 02117 // Write 02118 mhdf_writeSparseTagIndicesWithOpt( idx_table, offset, count, MHDF_INDEX_TYPE, idx_buffer, writeProp, &status ); 02119 CHK_MHDF_ERR_0( status ); 02120 02121 offset += count; 02122 --num_writes; 02123 } // while (remaining) 02124 02125 // Do empty writes if necessary for parallel collective IO 02126 if( collectiveIO ) 02127 { 02128 while( num_writes-- ) 02129 { 02130 assert( writeProp != H5P_DEFAULT ); 02131 dbgOut.print( 3, " writing empty sparse tag entity chunk.\n" ); 02132 mhdf_writeSparseTagIndicesWithOpt( idx_table, offset, 0, id_type, 0, writeProp, &status ); 02133 CHK_MHDF_ERR_0( status ); 02134 } 02135 } 02136 02137 track.all_reduce(); 02138 return MB_SUCCESS; 02139 } 02140 02141 ErrorCode WriteHDF5::write_var_len_data( const TagDesc& tag_data, 02142 const Range& range, 02143 hid_t table, 02144 size_t table_size, 02145 bool handle_tag, 02146 hid_t hdf_type, 02147 int type_size, 02148 const char* name ) 02149 { 02150 ErrorCode rval; 02151 mhdf_Status status; 02152 02153 CHECK_OPEN_HANDLES; 02154 assert( !handle_tag || sizeof( EntityHandle ) == type_size ); 02155 02156 std::string tname( name ? name : "<UNKNOWN TAG?>" ); 02157 tname += " - Values"; 02158 IODebugTrack track( debugTrack, tname, table_size ); 02159 02160 const size_t buffer_size = bufferSize / type_size; 02161 02162 size_t num_writes = ( table_size + buffer_size - 1 ) / buffer_size; 02163 if( collectiveIO ) 02164 { 02165 assert( tag_data.max_num_vals > 0 ); 02166 num_writes = ( tag_data.max_num_vals + buffer_size - 1 ) / buffer_size; 02167 } 02168 02169 unsigned char* buffer = (unsigned char*)dataBuffer; 02170 const void* prev_data = 0; // Data left over from prev iteration 02171 size_t prev_len = 0; 02172 Range::const_iterator iter = range.begin(); 02173 long offset = tag_data.var_data_offset; 02174 while( prev_data || iter != range.end() ) 02175 { 02176 size_t count = 0; 02177 if( prev_data ) 02178 { 02179 size_t len; 02180 const void* ptr = prev_data; 02181 if( prev_len <= buffer_size ) 02182 { 02183 len = prev_len; 02184 prev_data = 0; 02185 prev_len = 0; 02186 } 02187 else 02188 { 02189 len = buffer_size; 02190 prev_data = ( (const char*)prev_data ) + buffer_size * type_size; 02191 prev_len -= buffer_size; 02192 } 02193 02194 if( handle_tag ) 02195 convert_handle_tag( (const EntityHandle*)ptr, (EntityHandle*)buffer, len ); 02196 else 02197 memcpy( buffer, ptr, len * type_size ); 02198 count = len; 02199 } 02200 02201 for( ; count < buffer_size && iter != range.end(); ++iter ) 02202 { 02203 int len; 02204 const void* ptr; 02205 rval = iFace->tag_get_by_ptr( tag_data.tag_id, &*iter, 1, &ptr, &len ); 02206 CHK_MB_ERR_0( rval ); 02207 if( len + count > buffer_size ) 02208 { 02209 prev_len = len + count - buffer_size; 02210 len = buffer_size - count; 02211 prev_data = ( (const char*)ptr ) + len * type_size; 02212 } 02213 02214 if( handle_tag ) 02215 convert_handle_tag( (const EntityHandle*)ptr, ( (EntityHandle*)buffer ) + count, len ); 02216 else 02217 memcpy( buffer + count * type_size, ptr, len * type_size ); 02218 count += len; 02219 } 02220 02221 track.record_io( offset, count ); 02222 mhdf_writeTagValuesWithOpt( table, offset, count, hdf_type, buffer, writeProp, &status ); 02223 offset += count; 02224 CHK_MHDF_ERR_0( status ); 02225 --num_writes; 02226 } 02227 02228 // Do empty writes if necessary for parallel collective IO 02229 if( collectiveIO ) 02230 { 02231 while( num_writes-- ) 02232 { 02233 assert( writeProp != H5P_DEFAULT ); 02234 dbgOut.print( 3, " writing empty var-len tag data chunk.\n" ); 02235 mhdf_writeTagValuesWithOpt( table, 0, 0, hdf_type, 0, writeProp, &status ); 02236 CHK_MHDF_ERR_0( status ); 02237 } 02238 } 02239 02240 track.all_reduce(); 02241 return MB_SUCCESS; 02242 } 02243 02244 ErrorCode WriteHDF5::write_var_len_tag( const TagDesc& tag_data, 02245 const std::string& name, 02246 DataType mb_data_type, 02247 hid_t hdf_type, 02248 int type_size ) 02249 { 02250 ErrorCode rval; 02251 mhdf_Status status; 02252 hid_t tables[3]; 02253 long table_size; 02254 long data_table_size; 02255 02256 CHECK_OPEN_HANDLES; 02257 02258 // Get entities for which to write tag values 02259 Range range; 02260 rval = get_sparse_tagged_entities( tag_data, range ); 02261 02262 // Open tables to write info 02263 mhdf_openSparseTagData( filePtr, name.c_str(), &table_size, &data_table_size, tables, &status ); 02264 CHK_MHDF_ERR_0( status ); 02265 assert( range.size() + tag_data.sparse_offset <= (unsigned long)table_size ); 02266 02267 // Write IDs for tagged entities 02268 subState.start( "writing ids for var-len tag: ", name.c_str() ); 02269 rval = write_sparse_ids( tag_data, range, tables[0], table_size, name.c_str() ); 02270 subState.end( rval ); 02271 CHK_MB_ERR_2( rval, tables, status ); 02272 mhdf_closeData( filePtr, tables[0], &status ); 02273 CHK_MHDF_ERR_2( status, tables + 1 ); 02274 02275 // Write offsets for tagged entities 02276 subState.start( "writing indices for var-len tag: ", name.c_str() ); 02277 rval = write_var_len_indices( tag_data, range, tables[2], table_size, type_size, name.c_str() ); 02278 subState.end( rval ); 02279 CHK_MB_ERR_1( rval, tables[1], status ); 02280 mhdf_closeData( filePtr, tables[2], &status ); 02281 CHK_MHDF_ERR_1( status, tables[1] ); 02282 02283 // Write the actual tag data 02284 subState.start( "writing values for var-len tag: ", name.c_str() ); 02285 rval = write_var_len_data( tag_data, range, tables[1], data_table_size, mb_data_type == MB_TYPE_HANDLE, hdf_type, 02286 type_size, name.c_str() ); 02287 subState.end( rval ); 02288 CHK_MB_ERR_0( rval ); 02289 mhdf_closeData( filePtr, tables[1], &status ); 02290 CHK_MHDF_ERR_0( status ); 02291 02292 return MB_SUCCESS; 02293 } 02294 02295 ErrorCode WriteHDF5::write_dense_tag( const TagDesc& tag_data, 02296 const ExportSet& elem_data, 02297 const std::string& name, 02298 DataType mb_data_type, 02299 hid_t value_type, 02300 int value_type_size ) 02301 { 02302 CHECK_OPEN_HANDLES; 02303 02304 // Open tables to write info 02305 mhdf_Status status; 02306 long table_size; 02307 hid_t table = mhdf_openDenseTagData( filePtr, name.c_str(), elem_data.name(), &table_size, &status ); 02308 CHK_MHDF_ERR_0( status ); 02309 assert( elem_data.range.size() + elem_data.offset <= (unsigned long)table_size ); 02310 02311 IODebugTrack track( debugTrack, name + " " + elem_data.name() + " Data", table_size ); 02312 ErrorCode rval = write_tag_values( tag_data.tag_id, table, elem_data.offset, elem_data.range, mb_data_type, 02313 value_type, value_type_size, elem_data.max_num_ents, track ); 02314 CHK_MB_ERR_0( rval ); 02315 mhdf_closeData( filePtr, table, &status ); 02316 CHK_MHDF_ERR_0( status ); 02317 02318 return MB_SUCCESS; 02319 } 02320 02321 ErrorCode WriteHDF5::write_tag_values( Tag tag_id, 02322 hid_t data_table, 02323 unsigned long offset_in, 02324 const Range& range_in, 02325 DataType mb_data_type, 02326 hid_t value_type, 02327 int value_type_size, 02328 unsigned long max_num_ents, 02329 IODebugTrack& track ) 02330 { 02331 mhdf_Status status; 02332 02333 CHECK_OPEN_HANDLES; 02334 02335 // Set up data buffer for writing tag values 02336 size_t chunk_size = bufferSize / value_type_size; 02337 assert( chunk_size > 0 ); 02338 char* tag_buffer = (char*)dataBuffer; 02339 02340 // Write the tag values 02341 size_t remaining = range_in.size(); 02342 size_t offset = offset_in; 02343 Range::const_iterator iter = range_in.begin(); 02344 long num_writes = ( remaining + chunk_size - 1 ) / chunk_size; 02345 if( max_num_ents ) 02346 { 02347 assert( max_num_ents >= remaining ); 02348 num_writes = ( max_num_ents + chunk_size - 1 ) / chunk_size; 02349 } 02350 while( remaining ) 02351 { 02352 (void)VALGRIND_MAKE_MEM_UNDEFINED( dataBuffer, bufferSize ); 02353 02354 // Write "chunk_size" blocks of data 02355 long count = (unsigned long)remaining > chunk_size ? chunk_size : remaining; 02356 remaining -= count; 02357 memset( tag_buffer, 0, count * value_type_size ); 02358 Range::const_iterator stop = iter; 02359 stop += count; 02360 Range range; 02361 range.merge( iter, stop ); 02362 iter = stop; 02363 assert( range.size() == (unsigned)count ); 02364 02365 ErrorCode rval = iFace->tag_get_data( tag_id, range, tag_buffer ); 02366 CHK_MB_ERR_0( rval ); 02367 02368 // Convert EntityHandles to file ids 02369 if( mb_data_type == MB_TYPE_HANDLE ) 02370 convert_handle_tag( reinterpret_cast< EntityHandle* >( tag_buffer ), 02371 count * value_type_size / sizeof( EntityHandle ) ); 02372 02373 // Write the data 02374 dbgOut.print( 2, " writing tag value chunk.\n" ); 02375 track.record_io( offset, count ); 02376 assert( value_type > 0 ); 02377 mhdf_writeTagValuesWithOpt( data_table, offset, count, value_type, tag_buffer, writeProp, &status ); 02378 CHK_MHDF_ERR_0( status ); 02379 02380 offset += count; 02381 --num_writes; 02382 } // while (remaining) 02383 02384 // Do empty writes if necessary for parallel collective IO 02385 if( collectiveIO ) 02386 { 02387 while( num_writes-- ) 02388 { 02389 assert( writeProp != H5P_DEFAULT ); 02390 dbgOut.print( 2, " writing empty tag value chunk.\n" ); 02391 assert( value_type > 0 ); 02392 mhdf_writeTagValuesWithOpt( data_table, offset, 0, value_type, 0, writeProp, &status ); 02393 CHK_MHDF_ERR_0( status ); 02394 } 02395 } 02396 02397 track.all_reduce(); 02398 return MB_SUCCESS; 02399 } 02400 02401 ErrorCode WriteHDF5::write_qa( const std::vector< std::string >& list ) 02402 { 02403 const char* app = "MOAB"; 02404 const char* vers = MOAB_VERSION; 02405 char date_str[64]; 02406 char time_str[64]; 02407 02408 CHECK_OPEN_HANDLES; 02409 02410 std::vector< const char* > strs( list.size() ? list.size() : 4 ); 02411 if( list.size() == 0 ) 02412 { 02413 time_t t = time( NULL ); 02414 tm* lt = localtime( &t ); 02415 #ifdef WIN32 02416 strftime( date_str, sizeof( date_str ), "%m/%d/%y", lt ); // VS 2008 does not support %D 02417 strftime( time_str, sizeof( time_str ), "%H:%M:%S", lt ); // VS 2008 does not support %T 02418 #else 02419 strftime( date_str, sizeof( date_str ), "%D", lt ); 02420 strftime( time_str, sizeof( time_str ), "%T", lt ); 02421 #endif 02422 02423 strs[0] = app; 02424 strs[1] = vers; 02425 strs[2] = date_str; 02426 strs[3] = time_str; 02427 } 02428 else 02429 { 02430 for( unsigned int i = 0; i < list.size(); ++i ) 02431 strs[i] = list[i].c_str(); 02432 } 02433 02434 mhdf_Status status; 02435 dbgOut.print( 2, " writing QA history.\n" ); 02436 mhdf_writeHistory( filePtr, &strs[0], strs.size(), &status ); 02437 CHK_MHDF_ERR_0( status ); 02438 02439 return MB_SUCCESS; 02440 } 02441 02442 /* 02443 ErrorCode WriteHDF5::register_known_tag_types(Interface* iface) 02444 { 02445 hid_t int4, double16; 02446 hsize_t dim[1]; 02447 int error = 0; 02448 ErrorCode rval; 02449 02450 dim[0] = 4; 02451 int4 = H5Tarray_create(H5T_NATIVE_INT, 1, dim, NULL); 02452 02453 dim[0] = 16; 02454 double16 = H5Tarray_create(H5T_NATIVE_DOUBLE, 1, dim, NULL); 02455 02456 if (int4 < 0 || double16 < 0) 02457 error = 1; 02458 02459 struct { const char* name; hid_t type; } list[] = { 02460 { GLOBAL_ID_TAG_NAME, H5T_NATIVE_INT } , 02461 { MATERIAL_SET_TAG_NAME, H5T_NATIVE_INT }, 02462 { DIRICHLET_SET_TAG_NAME, H5T_NATIVE_INT }, 02463 { NEUMANN_SET_TAG_NAME, H5T_NATIVE_INT }, 02464 { HAS_MID_NODES_TAG_NAME, int4 }, 02465 { GEOM_DIMENSION_TAG_NAME, H5T_NATIVE_INT }, 02466 { MESH_TRANSFORM_TAG_NAME, double16 }, 02467 { 0, 0 } }; 02468 02469 for (int i = 0; list[i].name; ++i) { 02470 if (list[i].type < 1) { 02471 ++error; 02472 continue; 02473 } 02474 02475 Tag handle; 02476 02477 std::string name("__hdf5_tag_type_"); 02478 name += list[i].name; 02479 02480 rval = iface->tag_get_handle(name.c_str(), handle); 02481 if (MB_TAG_NOT_FOUND == rval) { 02482 rval = iface->tag_create(name.c_str(), sizeof(hid_t), MB_TAG_SPARSE, handle, NULL); 02483 if (MB_SUCCESS != rval) { 02484 ++error; 02485 continue; 02486 } 02487 02488 hid_t copy_id = H5Tcopy(list[i].type); 02489 const EntityHandle mesh = 0; 02490 rval = iface->tag_set_data(handle, &mesh, 1, ©_id); 02491 if (MB_SUCCESS != rval) { 02492 ++error; 02493 continue; 02494 } 02495 } 02496 } 02497 02498 H5Tclose(int4); 02499 H5Tclose(double16); 02500 return error ? MB_FAILURE : MB_SUCCESS; 02501 } 02502 */ 02503 02504 ErrorCode WriteHDF5::gather_tags( const Tag* user_tag_list, int num_tags ) 02505 { 02506 ErrorCode result; 02507 std::vector< Tag > tag_list; 02508 std::vector< Tag >::iterator t_itor; 02509 Range range; 02510 02511 // Get list of Tags to write 02512 result = writeUtil->get_tag_list( tag_list, user_tag_list, num_tags ); 02513 CHK_MB_ERR_0( result ); 02514 02515 // Get list of tags 02516 for( t_itor = tag_list.begin(); t_itor != tag_list.end(); ++t_itor ) 02517 { 02518 // Add tag to export list 02519 TagDesc tag_data; 02520 tag_data.write_sparse = false; 02521 tag_data.tag_id = *t_itor; 02522 tag_data.sparse_offset = 0; 02523 tag_data.var_data_offset = 0; 02524 tag_data.max_num_ents = 0; 02525 tag_data.max_num_vals = 0; 02526 tagList.push_back( tag_data ); 02527 } 02528 02529 return MB_SUCCESS; 02530 } 02531 02532 // If we support parallel, then this function will have been 02533 // overridden with an alternate version in WriteHDF5Parallel 02534 // that supports parallel I/O. If we're here 02535 // then MOAB was not built with support for parallel HDF5 I/O. 02536 ErrorCode WriteHDF5::parallel_create_file( const char* /* filename */, 02537 bool /* overwrite */, 02538 const std::vector< std::string >& /* qa_records */, 02539 const FileOptions& /* opts */, 02540 const Tag* /* tag_list */, 02541 int /* num_tags */, 02542 int /* dimension */, 02543 double* /* times */ ) 02544 { 02545 MB_SET_ERR( MB_NOT_IMPLEMENTED, "WriteHDF5 does not support parallel writing" ); 02546 } 02547 02548 ErrorCode WriteHDF5::serial_create_file( const char* filename, 02549 bool overwrite, 02550 const std::vector< std::string >& qa_records, 02551 const Tag* user_tag_list, 02552 int num_user_tags, 02553 int dimension ) 02554 { 02555 long first_id; 02556 mhdf_Status status; 02557 hid_t handle; 02558 std::list< ExportSet >::iterator ex_itor; 02559 ErrorCode rval; 02560 02561 topState.start( "creating file" ); 02562 02563 const char* type_names[MBMAXTYPE]; 02564 memset( type_names, 0, MBMAXTYPE * sizeof( char* ) ); 02565 for( EntityType i = MBEDGE; i < MBENTITYSET; ++i ) 02566 type_names[i] = CN::EntityTypeName( i ); 02567 02568 // Create the file 02569 filePtr = mhdf_createFile( filename, overwrite, type_names, MBMAXTYPE, id_type, &status ); 02570 CHK_MHDF_ERR_0( status ); 02571 assert( !!filePtr ); 02572 02573 rval = write_qa( qa_records ); 02574 CHK_MB_ERR_0( rval ); 02575 02576 // Create node table 02577 if( nodeSet.range.size() ) 02578 { 02579 nodeSet.total_num_ents = nodeSet.range.size(); 02580 handle = mhdf_createNodeCoords( filePtr, dimension, nodeSet.total_num_ents, &first_id, &status ); 02581 CHK_MHDF_ERR_0( status ); 02582 mhdf_closeData( filePtr, handle, &status ); 02583 CHK_MHDF_ERR_0( status ); 02584 nodeSet.first_id = (wid_t)first_id; 02585 rval = assign_ids( nodeSet.range, nodeSet.first_id ); 02586 CHK_MB_ERR_0( rval ); 02587 } 02588 else 02589 { 02590 nodeSet.first_id = std::numeric_limits< wid_t >::max(); 02591 } 02592 nodeSet.offset = 0; 02593 02594 // Create element tables 02595 for( ex_itor = exportList.begin(); ex_itor != exportList.end(); ++ex_itor ) 02596 { 02597 ex_itor->total_num_ents = ex_itor->range.size(); 02598 rval = create_elem_table( *ex_itor, ex_itor->total_num_ents, first_id ); 02599 CHK_MB_ERR_0( rval ); 02600 02601 ex_itor->first_id = (wid_t)first_id; 02602 ex_itor->offset = 0; 02603 rval = assign_ids( ex_itor->range, ex_itor->first_id ); 02604 CHK_MB_ERR_0( rval ); 02605 } 02606 // Create set tables 02607 writeSets = !setSet.range.empty(); 02608 if( writeSets ) 02609 { 02610 long contents_len, children_len, parents_len; 02611 02612 setSet.total_num_ents = setSet.range.size(); 02613 setSet.max_num_ents = setSet.total_num_ents; 02614 rval = create_set_meta( setSet.total_num_ents, first_id ); 02615 CHK_MB_ERR_0( rval ); 02616 02617 setSet.first_id = (wid_t)first_id; 02618 rval = assign_ids( setSet.range, setSet.first_id ); 02619 CHK_MB_ERR_0( rval ); 02620 02621 rval = count_set_size( setSet.range, contents_len, children_len, parents_len ); 02622 CHK_MB_ERR_0( rval ); 02623 02624 rval = create_set_tables( contents_len, children_len, parents_len ); 02625 CHK_MB_ERR_0( rval ); 02626 02627 setSet.offset = 0; 02628 setContentsOffset = 0; 02629 setChildrenOffset = 0; 02630 setParentsOffset = 0; 02631 writeSetContents = !!contents_len; 02632 writeSetChildren = !!children_len; 02633 writeSetParents = !!parents_len; 02634 02635 maxNumSetContents = contents_len; 02636 maxNumSetChildren = children_len; 02637 maxNumSetParents = parents_len; 02638 } // if (!setSet.range.empty()) 02639 02640 // Create adjacency table after set table, because sets do not have yet an id 02641 // some entities are adjacent to sets (exodus?) 02642 // Create node adjacency table 02643 wid_t num_adjacencies; 02644 #ifdef MB_H5M_WRITE_NODE_ADJACENCIES 02645 rval = count_adjacencies( nodeSet.range, num_adjacencies ); 02646 CHK_MB_ERR_0( rval ); 02647 nodeSet.adj_offset = 0; 02648 nodeSet.max_num_adjs = num_adjacencies; 02649 if( num_adjacencies > 0 ) 02650 { 02651 handle = mhdf_createAdjacency( filePtr, mhdf_node_type_handle(), num_adjacencies, &status ); 02652 CHK_MHDF_ERR_0( status ); 02653 mhdf_closeData( filePtr, handle, &status ); 02654 } 02655 #endif 02656 02657 // Create element adjacency tables 02658 for( ex_itor = exportList.begin(); ex_itor != exportList.end(); ++ex_itor ) 02659 { 02660 rval = count_adjacencies( ex_itor->range, num_adjacencies ); 02661 CHK_MB_ERR_0( rval ); 02662 02663 ex_itor->adj_offset = 0; 02664 ex_itor->max_num_adjs = num_adjacencies; 02665 if( num_adjacencies > 0 ) 02666 { 02667 handle = mhdf_createAdjacency( filePtr, ex_itor->name(), num_adjacencies, &status ); 02668 CHK_MHDF_ERR_0( status ); 02669 mhdf_closeData( filePtr, handle, &status ); 02670 } 02671 } 02672 02673 dbgOut.tprint( 1, "Gathering Tags\n" ); 02674 02675 rval = gather_tags( user_tag_list, num_user_tags ); 02676 CHK_MB_ERR_0( rval ); 02677 02678 // Create the tags and tag data tables 02679 std::list< TagDesc >::iterator tag_iter = tagList.begin(); 02680 for( ; tag_iter != tagList.end(); ++tag_iter ) 02681 { 02682 // As we haven't yet added any ExportSets for which to write 02683 // dense tag data to the TagDesc struct pointed to by 02684 // tag_iter, this call will initially return all tagged entities 02685 // in the set of entities to be written. 02686 Range range; 02687 rval = get_sparse_tagged_entities( *tag_iter, range ); 02688 CHK_MB_ERR_0( rval ); 02689 02690 int s; 02691 bool var_len = ( MB_VARIABLE_DATA_LENGTH == iFace->tag_get_length( tag_iter->tag_id, s ) ); 02692 02693 // Determine which ExportSets we want to write dense 02694 // data for. We never write dense data for variable-length 02695 // tag data. 02696 if( !var_len && writeTagDense ) 02697 { 02698 // Check if we want to write this tag in dense format even if not 02699 // all of the entities have a tag value. The criterion of this 02700 // is that the tag be dense, have a default value, and have at 02701 // least 2/3 of the entities tagged. 02702 bool prefer_dense = false; 02703 TagType type; 02704 rval = iFace->tag_get_type( tag_iter->tag_id, type ); 02705 CHK_MB_ERR_0( rval ); 02706 if( MB_TAG_DENSE == type ) 02707 { 02708 const void* defval = 0; 02709 rval = iFace->tag_get_default_value( tag_iter->tag_id, defval, s ); 02710 if( MB_SUCCESS == rval ) prefer_dense = true; 02711 } 02712 02713 if( check_dense_format_tag( nodeSet, range, prefer_dense ) ) 02714 { 02715 range -= nodeSet.range; 02716 tag_iter->dense_list.push_back( nodeSet ); 02717 } 02718 02719 std::list< ExportSet >::const_iterator ex = exportList.begin(); 02720 for( ; ex != exportList.end(); ++ex ) 02721 { 02722 if( check_dense_format_tag( *ex, range, prefer_dense ) ) 02723 { 02724 range -= ex->range; 02725 tag_iter->dense_list.push_back( *ex ); 02726 } 02727 } 02728 02729 if( check_dense_format_tag( setSet, range, prefer_dense ) ) 02730 { 02731 range -= setSet.range; 02732 tag_iter->dense_list.push_back( setSet ); 02733 } 02734 } 02735 02736 tag_iter->write_sparse = !range.empty(); 02737 02738 unsigned long var_len_total = 0; 02739 if( var_len ) 02740 { 02741 rval = get_tag_data_length( *tag_iter, range, var_len_total ); 02742 CHK_MB_ERR_0( rval ); 02743 } 02744 02745 rval = create_tag( *tag_iter, range.size(), var_len_total ); 02746 CHK_MB_ERR_0( rval ); 02747 } // for (tags) 02748 02749 topState.end(); 02750 return MB_SUCCESS; 02751 } 02752 02753 bool WriteHDF5::check_dense_format_tag( const ExportSet& ents, const Range& all_tagged, bool prefer_dense ) 02754 { 02755 // If there are no tagged entities, then don't write anything 02756 if( ents.range.empty() ) return false; 02757 02758 // If all of the entities are tagged, then write in dense format 02759 if( all_tagged.contains( ents.range ) ) return true; 02760 02761 // Unless asked for more lenient choice of dense format, return false 02762 if( !prefer_dense ) return false; 02763 02764 // If we're being lenient about choosing dense format, then 02765 // return true if at least 2/3 of the entities are tagged. 02766 Range xsect = intersect( setSet.range, all_tagged ); 02767 if( 3 * xsect.size() >= 2 * setSet.range.size() ) return true; 02768 02769 return false; 02770 } 02771 02772 ErrorCode WriteHDF5::count_adjacencies( const Range& set, wid_t& result ) 02773 { 02774 ErrorCode rval; 02775 std::vector< wid_t > adj_list; 02776 Range::const_iterator iter = set.begin(); 02777 const Range::const_iterator end = set.end(); 02778 result = 0; 02779 for( ; iter != end; ++iter ) 02780 { 02781 adj_list.clear(); 02782 rval = get_adjacencies( *iter, adj_list ); 02783 CHK_MB_ERR_0( rval ); 02784 02785 if( adj_list.size() > 0 ) result += 2 + adj_list.size(); 02786 } 02787 02788 return MB_SUCCESS; 02789 } 02790 02791 ErrorCode WriteHDF5::create_elem_table( const ExportSet& block, long num_entities, long& first_id_out ) 02792 { 02793 mhdf_Status status; 02794 hid_t handle; 02795 02796 CHECK_OPEN_HANDLES; 02797 02798 mhdf_addElement( filePtr, block.name(), block.type, &status ); 02799 CHK_MHDF_ERR_0( status ); 02800 02801 handle = mhdf_createConnectivity( filePtr, block.name(), block.num_nodes, num_entities, &first_id_out, &status ); 02802 CHK_MHDF_ERR_0( status ); 02803 mhdf_closeData( filePtr, handle, &status ); 02804 CHK_MHDF_ERR_0( status ); 02805 02806 return MB_SUCCESS; 02807 } 02808 02809 ErrorCode WriteHDF5::count_set_size( const Range& sets, 02810 long& contents_length_out, 02811 long& children_length_out, 02812 long& parents_length_out ) 02813 { 02814 ErrorCode rval; 02815 Range set_contents; 02816 long contents_length_set, children_length_set, parents_length_set; 02817 unsigned long flags; 02818 std::vector< wid_t > set_contents_ids; 02819 std::vector< SpecialSetData >::const_iterator si = specialSets.begin(); 02820 02821 contents_length_out = 0; 02822 children_length_out = 0; 02823 parents_length_out = 0; 02824 02825 for( Range::const_iterator iter = sets.begin(); iter != sets.end(); ++iter ) 02826 { 02827 while( si != specialSets.end() && si->setHandle < *iter ) 02828 ++si; 02829 02830 if( si != specialSets.end() && si->setHandle == *iter ) 02831 { 02832 contents_length_out += si->contentIds.size(); 02833 children_length_out += si->childIds.size(); 02834 parents_length_out += si->parentIds.size(); 02835 ++si; 02836 continue; 02837 } 02838 02839 rval = get_set_info( *iter, contents_length_set, children_length_set, parents_length_set, flags ); 02840 CHK_MB_ERR_0( rval ); 02841 02842 // Check if can and should compress as ranges 02843 if( !( flags & MESHSET_ORDERED ) && contents_length_set ) 02844 { 02845 set_contents.clear(); 02846 rval = iFace->get_entities_by_handle( *iter, set_contents, false ); 02847 CHK_MB_ERR_0( rval ); 02848 02849 bool blocked_list; 02850 rval = range_to_blocked_list( set_contents, set_contents_ids, blocked_list ); 02851 CHK_MB_ERR_0( rval ); 02852 02853 if( blocked_list ) 02854 { 02855 assert( set_contents_ids.size() % 2 == 0 ); 02856 contents_length_set = set_contents_ids.size(); 02857 } 02858 } 02859 02860 contents_length_out += contents_length_set; 02861 children_length_out += children_length_set; 02862 parents_length_out += parents_length_set; 02863 } 02864 02865 return MB_SUCCESS; 02866 } 02867 02868 ErrorCode WriteHDF5::create_set_meta( long num_sets, long& first_id_out ) 02869 { 02870 hid_t handle; 02871 mhdf_Status status; 02872 02873 CHECK_OPEN_HANDLES; 02874 02875 handle = mhdf_createSetMeta( filePtr, num_sets, &first_id_out, &status ); 02876 CHK_MHDF_ERR_0( status ); 02877 mhdf_closeData( filePtr, handle, &status ); 02878 02879 return MB_SUCCESS; 02880 } 02881 02882 WriteHDF5::SpecialSetData* WriteHDF5::find_set_data( EntityHandle h ) 02883 { 02884 SpecialSetData tmp; 02885 tmp.setHandle = h; 02886 std::vector< SpecialSetData >::iterator i; 02887 i = std::lower_bound( specialSets.begin(), specialSets.end(), tmp, SpecSetLess() ); 02888 return ( i == specialSets.end() || i->setHandle != h ) ? 0 : &*i; 02889 } 02890 02891 ErrorCode WriteHDF5::create_set_tables( long num_set_contents, long num_set_children, long num_set_parents ) 02892 { 02893 hid_t handle; 02894 mhdf_Status status; 02895 02896 CHECK_OPEN_HANDLES; 02897 02898 if( num_set_contents > 0 ) 02899 { 02900 handle = mhdf_createSetData( filePtr, num_set_contents, &status ); 02901 CHK_MHDF_ERR_0( status ); 02902 mhdf_closeData( filePtr, handle, &status ); 02903 } 02904 02905 if( num_set_children > 0 ) 02906 { 02907 handle = mhdf_createSetChildren( filePtr, num_set_children, &status ); 02908 CHK_MHDF_ERR_0( status ); 02909 mhdf_closeData( filePtr, handle, &status ); 02910 } 02911 02912 if( num_set_parents > 0 ) 02913 { 02914 handle = mhdf_createSetParents( filePtr, num_set_parents, &status ); 02915 CHK_MHDF_ERR_0( status ); 02916 mhdf_closeData( filePtr, handle, &status ); 02917 } 02918 02919 return MB_SUCCESS; 02920 } 02921 02922 ErrorCode WriteHDF5::get_tag_size( Tag tag, 02923 DataType& moab_type, 02924 int& num_bytes, 02925 int& type_size, 02926 int& array_length, 02927 mhdf_TagDataType& file_type, 02928 hid_t& hdf_type ) 02929 { 02930 ErrorCode rval; 02931 Tag type_handle; 02932 std::string tag_name, tag_type_name; 02933 02934 CHECK_OPEN_HANDLES; 02935 02936 // We return NULL for hdf_type if it can be determined from 02937 // the file_type. The only case where it is non-zero is 02938 // if the user specified a specific type via a mesh tag. 02939 hdf_type = (hid_t)0; 02940 bool close_hdf_type = false; 02941 02942 rval = iFace->tag_get_data_type( tag, moab_type ); 02943 CHK_MB_ERR_0( rval ); 02944 rval = iFace->tag_get_length( tag, array_length ); 02945 if( MB_VARIABLE_DATA_LENGTH == rval ) 02946 { 02947 array_length = MB_VARIABLE_LENGTH; 02948 } 02949 else if( MB_SUCCESS != rval ) 02950 return error( rval ); 02951 rval = iFace->tag_get_bytes( tag, num_bytes ); 02952 if( MB_VARIABLE_DATA_LENGTH == rval ) 02953 num_bytes = MB_VARIABLE_LENGTH; 02954 else if( MB_SUCCESS != rval ) 02955 return error( rval ); 02956 02957 switch( moab_type ) 02958 { 02959 case MB_TYPE_INTEGER: 02960 type_size = sizeof( int ); 02961 file_type = mhdf_INTEGER; 02962 hdf_type = H5T_NATIVE_INT; 02963 close_hdf_type = false; 02964 break; 02965 case MB_TYPE_DOUBLE: 02966 type_size = sizeof( double ); 02967 file_type = mhdf_FLOAT; 02968 hdf_type = H5T_NATIVE_DOUBLE; 02969 close_hdf_type = false; 02970 break; 02971 case MB_TYPE_BIT: 02972 type_size = sizeof( bool ); 02973 file_type = mhdf_BITFIELD; 02974 assert( array_length <= 8 ); 02975 hdf_type = H5Tcopy( H5T_NATIVE_B8 ); 02976 H5Tset_precision( hdf_type, array_length ); 02977 close_hdf_type = true; 02978 break; 02979 case MB_TYPE_HANDLE: 02980 type_size = sizeof( EntityHandle ); 02981 file_type = mhdf_ENTITY_ID; 02982 hdf_type = id_type; 02983 close_hdf_type = false; 02984 break; 02985 case MB_TYPE_OPAQUE: 02986 file_type = mhdf_OPAQUE; 02987 rval = iFace->tag_get_name( tag, tag_name ); 02988 CHK_MB_ERR_0( rval ); 02989 tag_type_name = "__hdf5_tag_type_"; 02990 tag_type_name += tag_name; 02991 rval = iFace->tag_get_handle( tag_type_name.c_str(), 0, MB_TYPE_OPAQUE, type_handle, MB_TAG_ANY ); 02992 if( MB_TAG_NOT_FOUND == rval ) 02993 { 02994 if( num_bytes == MB_VARIABLE_LENGTH ) 02995 type_size = 1; 02996 else 02997 type_size = num_bytes; 02998 hdf_type = H5Tcreate( H5T_OPAQUE, type_size ); 02999 close_hdf_type = true; 03000 } 03001 else if( MB_SUCCESS == rval ) 03002 { 03003 int hsize; 03004 rval = iFace->tag_get_bytes( type_handle, hsize ); 03005 if( hsize != sizeof( hid_t ) ) return error( MB_FAILURE ); 03006 03007 const EntityHandle root = 0; 03008 rval = iFace->tag_get_data( type_handle, &root, 1, &hdf_type ); 03009 if( rval != MB_SUCCESS ) return error( rval ); 03010 03011 type_size = H5Tget_size( hdf_type ); 03012 if( type_size != num_bytes ) return error( MB_FAILURE ); 03013 03014 close_hdf_type = false; 03015 } 03016 else 03017 return error( rval ); 03018 num_bytes = array_length; 03019 array_length = ( num_bytes == MB_VARIABLE_LENGTH ) ? MB_VARIABLE_LENGTH : 1; 03020 break; 03021 default: 03022 break; 03023 } 03024 03025 assert( num_bytes == MB_VARIABLE_LENGTH || ( moab_type == MB_TYPE_BIT && num_bytes == 1 ) || 03026 array_length * type_size == num_bytes ); 03027 03028 if( num_bytes == MB_VARIABLE_LENGTH ) 03029 { 03030 array_length = MB_VARIABLE_LENGTH; 03031 if( !close_hdf_type ) 03032 { 03033 hdf_type = H5Tcopy( hdf_type ); 03034 // close_hdf_type = true; 03035 } 03036 } 03037 else if( array_length > 1 && moab_type != MB_TYPE_BIT ) 03038 { 03039 hsize_t len = array_length; 03040 #if defined( H5Tarray_create_vers ) && ( H5Tarray_create_vers > 1 ) 03041 hid_t temp_id = H5Tarray_create2( hdf_type, 1, &len ); 03042 #else 03043 hid_t temp_id = H5Tarray_create( hdf_type, 1, &len, NULL ); 03044 #endif 03045 if( close_hdf_type ) H5Tclose( hdf_type ); 03046 hdf_type = temp_id; 03047 } 03048 else if( !close_hdf_type ) 03049 { 03050 hdf_type = H5Tcopy( hdf_type ); 03051 // close_hdf_type = true; 03052 } 03053 03054 return MB_SUCCESS; 03055 } 03056 03057 ErrorCode WriteHDF5::get_tag_data_length( const TagDesc& tag_info, const Range& range, unsigned long& result ) 03058 { 03059 ErrorCode rval; 03060 result = 0; 03061 03062 // Split buffer into two pieces, one for pointers and one for sizes 03063 size_t step, remaining; 03064 step = bufferSize / ( sizeof( int ) + sizeof( void* ) ); 03065 const void** ptr_buffer = reinterpret_cast< const void** >( dataBuffer ); 03066 int* size_buffer = reinterpret_cast< int* >( ptr_buffer + step ); 03067 Range subrange; 03068 Range::const_iterator iter = range.begin(); 03069 for( remaining = range.size(); remaining >= step; remaining -= step ) 03070 { 03071 // Get subset of range containing 'count' entities 03072 Range::const_iterator end = iter; 03073 end += step; 03074 subrange.clear(); 03075 subrange.merge( iter, end ); 03076 iter = end; 03077 // Get tag sizes for entities 03078 rval = iFace->tag_get_by_ptr( tag_info.tag_id, subrange, ptr_buffer, size_buffer ); 03079 if( MB_SUCCESS != rval ) return error( rval ); 03080 // Sum lengths 03081 for( size_t i = 0; i < step; ++i ) 03082 result += size_buffer[i]; 03083 } 03084 // Process remaining 03085 subrange.clear(); 03086 subrange.merge( iter, range.end() ); 03087 assert( subrange.size() == remaining ); 03088 rval = iFace->tag_get_by_ptr( tag_info.tag_id, subrange, ptr_buffer, size_buffer ); 03089 if( MB_SUCCESS != rval ) return error( rval ); 03090 for( size_t i = 0; i < remaining; ++i ) 03091 result += size_buffer[i]; 03092 03093 return MB_SUCCESS; 03094 } 03095 03096 ErrorCode WriteHDF5::create_tag( const TagDesc& tag_data, 03097 unsigned long num_sparse_entities, 03098 unsigned long data_table_size ) 03099 { 03100 TagType mb_storage; 03101 DataType mb_type; 03102 mhdf_TagDataType mhdf_type; 03103 int tag_bytes, type_size, num_vals, storage; 03104 hid_t hdf_type = (hid_t)0; 03105 hid_t handles[3]; 03106 std::string tag_name; 03107 ErrorCode rval; 03108 mhdf_Status status; 03109 03110 CHECK_OPEN_HANDLES; 03111 03112 // Get tag properties 03113 rval = iFace->tag_get_type( tag_data.tag_id, mb_storage ); 03114 CHK_MB_ERR_0( rval ); 03115 switch( mb_storage ) 03116 { 03117 case MB_TAG_DENSE: 03118 storage = mhdf_DENSE_TYPE; 03119 break; 03120 case MB_TAG_SPARSE: 03121 storage = mhdf_SPARSE_TYPE; 03122 break; 03123 case MB_TAG_BIT: 03124 storage = mhdf_BIT_TYPE; 03125 break; 03126 case MB_TAG_MESH: 03127 storage = mhdf_MESH_TYPE; 03128 break; 03129 default: 03130 return error( MB_FAILURE ); 03131 } 03132 rval = iFace->tag_get_name( tag_data.tag_id, tag_name ); 03133 CHK_MB_ERR_0( rval ); 03134 rval = get_tag_size( tag_data.tag_id, mb_type, tag_bytes, type_size, num_vals, mhdf_type, hdf_type ); 03135 CHK_MB_ERR_0( rval ); 03136 03137 // Get default value 03138 const void *def_value, *mesh_value; 03139 int def_val_len, mesh_val_len; 03140 rval = iFace->tag_get_default_value( tag_data.tag_id, def_value, def_val_len ); 03141 if( MB_ENTITY_NOT_FOUND == rval ) 03142 { 03143 def_value = 0; 03144 def_val_len = 0; 03145 } 03146 else if( MB_SUCCESS != rval ) 03147 { 03148 H5Tclose( hdf_type ); 03149 return error( rval ); 03150 } 03151 03152 // Get mesh value 03153 unsigned char byte; 03154 const EntityHandle root = 0; 03155 if( mb_storage == MB_TAG_BIT ) 03156 { 03157 rval = iFace->tag_get_data( tag_data.tag_id, &root, 1, &byte ); 03158 mesh_value = &byte; 03159 mesh_val_len = 1; 03160 } 03161 else 03162 { 03163 rval = iFace->tag_get_by_ptr( tag_data.tag_id, &root, 1, &mesh_value, &mesh_val_len ); 03164 } 03165 if( MB_TAG_NOT_FOUND == rval ) 03166 { 03167 mesh_value = 0; 03168 mesh_val_len = 0; 03169 } 03170 else if( MB_SUCCESS != rval ) 03171 { 03172 H5Tclose( hdf_type ); 03173 return error( rval ); 03174 } 03175 03176 // For handle-type tags, need to convert from handles to file ids 03177 if( MB_TYPE_HANDLE == mb_type ) 03178 { 03179 // Make sure there's room in the buffer for both 03180 assert( ( def_val_len + mesh_val_len ) * sizeof( long ) < (size_t)bufferSize ); 03181 03182 // Convert default value 03183 if( def_value ) 03184 { 03185 memcpy( dataBuffer, def_value, def_val_len * sizeof( EntityHandle ) ); 03186 convert_handle_tag( reinterpret_cast< EntityHandle* >( dataBuffer ), def_val_len ); 03187 def_value = dataBuffer; 03188 } 03189 03190 // Convert mesh value 03191 if( mesh_value ) 03192 { 03193 EntityHandle* ptr = reinterpret_cast< EntityHandle* >( dataBuffer ) + def_val_len; 03194 memcpy( ptr, mesh_value, mesh_val_len * sizeof( EntityHandle ) ); 03195 if( convert_handle_tag( ptr, mesh_val_len ) ) 03196 mesh_value = ptr; 03197 else 03198 mesh_value = 0; 03199 } 03200 } 03201 03202 if( MB_VARIABLE_LENGTH != tag_bytes ) 03203 { 03204 // Write the tag description to the file 03205 mhdf_createTag( filePtr, tag_name.c_str(), mhdf_type, num_vals, storage, def_value, mesh_value, hdf_type, 03206 mb_type == MB_TYPE_HANDLE ? id_type : 0, &status ); 03207 CHK_MHDF_ERR_0( status ); 03208 H5Tclose( hdf_type ); 03209 03210 // Create empty table for tag data 03211 if( num_sparse_entities ) 03212 { 03213 mhdf_createSparseTagData( filePtr, tag_name.c_str(), num_sparse_entities, handles, &status ); 03214 CHK_MHDF_ERR_0( status ); 03215 mhdf_closeData( filePtr, handles[0], &status ); 03216 mhdf_closeData( filePtr, handles[1], &status ); 03217 } 03218 03219 for( size_t i = 0; i < tag_data.dense_list.size(); ++i ) 03220 { 03221 const ExportSet* ex = find( tag_data.dense_list[i] ); 03222 assert( 0 != ex ); 03223 handles[0] = mhdf_createDenseTagData( filePtr, tag_name.c_str(), ex->name(), ex->total_num_ents, &status ); 03224 CHK_MHDF_ERR_0( status ); 03225 mhdf_closeData( filePtr, handles[0], &status ); 03226 } 03227 } 03228 else 03229 { 03230 mhdf_createVarLenTag( filePtr, tag_name.c_str(), mhdf_type, storage, def_value, def_val_len, mesh_value, 03231 mesh_val_len, hdf_type, mb_type == MB_TYPE_HANDLE ? id_type : 0, &status ); 03232 CHK_MHDF_ERR_0( status ); 03233 H5Tclose( hdf_type ); 03234 03235 // Create empty table for tag data 03236 if( num_sparse_entities ) 03237 { 03238 mhdf_createVarLenTagData( filePtr, tag_name.c_str(), num_sparse_entities, data_table_size, handles, 03239 &status ); 03240 CHK_MHDF_ERR_0( status ); 03241 mhdf_closeData( filePtr, handles[0], &status ); 03242 mhdf_closeData( filePtr, handles[1], &status ); 03243 mhdf_closeData( filePtr, handles[2], &status ); 03244 } 03245 } 03246 03247 return MB_SUCCESS; 03248 } 03249 03250 ErrorCode WriteHDF5::get_num_sparse_tagged_entities( const TagDesc& tag, size_t& count ) 03251 { 03252 Range tmp; 03253 ErrorCode rval = get_sparse_tagged_entities( tag, tmp ); 03254 count = tmp.size(); 03255 return rval; 03256 } 03257 03258 ErrorCode WriteHDF5::get_sparse_tagged_entities( const TagDesc& tag, Range& results ) 03259 { 03260 results.clear(); 03261 if( !tag.have_dense( setSet ) ) results.merge( setSet.range ); 03262 std::list< ExportSet >::reverse_iterator e; 03263 for( e = exportList.rbegin(); e != exportList.rend(); ++e ) 03264 { 03265 if( !tag.have_dense( *e ) ) results.merge( e->range ); 03266 } 03267 if( !tag.have_dense( nodeSet ) ) results.merge( nodeSet.range ); 03268 if( results.empty() ) return MB_SUCCESS; 03269 03270 return iFace->get_entities_by_type_and_tag( 0, MBMAXTYPE, &tag.tag_id, 0, 1, results, Interface::INTERSECT ); 03271 } 03272 03273 void WriteHDF5::get_write_entities( Range& range ) 03274 { 03275 range.clear(); 03276 range.merge( setSet.range ); 03277 std::list< ExportSet >::reverse_iterator e; 03278 for( e = exportList.rbegin(); e != exportList.rend(); ++e ) 03279 range.merge( e->range ); 03280 range.merge( nodeSet.range ); 03281 } 03282 03283 void WriteHDF5::print_id_map() const 03284 { 03285 print_id_map( std::cout, "" ); 03286 } 03287 03288 void WriteHDF5::print_id_map( std::ostream& s, const char* pfx ) const 03289 { 03290 RangeMap< EntityHandle, wid_t >::const_iterator i; 03291 for( i = idMap.begin(); i != idMap.end(); ++i ) 03292 { 03293 const char* n1 = CN::EntityTypeName( TYPE_FROM_HANDLE( i->begin ) ); 03294 EntityID id = ID_FROM_HANDLE( i->begin ); 03295 if( 1 == i->count ) 03296 { 03297 s << pfx << n1 << " " << id << " -> " << i->value << std::endl; 03298 } 03299 else 03300 { 03301 const char* n2 = CN::EntityTypeName( TYPE_FROM_HANDLE( i->begin + i->count - 1 ) ); 03302 if( n1 == n2 ) 03303 { 03304 s << pfx << n1 << " " << id << "-" << id + i->count - 1 << " -> " << i->value << "-" 03305 << i->value + i->count - 1 << std::endl; 03306 } 03307 else 03308 { 03309 s << pfx << n1 << " " << id << "-" << n1 << " " << ID_FROM_HANDLE( i->begin + i->count - 1 ) << " -> " 03310 << i->value << "-" << i->value + i->count - 1 << std::endl; 03311 } 03312 } 03313 } 03314 } 03315 03316 void WriteHDF5::print_times( const double* t ) const 03317 { 03318 std::cout << "WriteHDF5: " << t[TOTAL_TIME] << std::endl 03319 << " gather mesh: " << t[GATHER_TIME] << std::endl 03320 << " create file: " << t[CREATE_TIME] << std::endl 03321 << " create nodes: " << t[CREATE_NODE_TIME] << std::endl 03322 << " negotiate types: " << t[NEGOTIATE_TYPES_TIME] << std::endl 03323 << " create elem: " << t[CREATE_ELEM_TIME] << std::endl 03324 << " file id exch: " << t[FILEID_EXCHANGE_TIME] << std::endl 03325 << " create adj: " << t[CREATE_ADJ_TIME] << std::endl 03326 << " create set: " << t[CREATE_SET_TIME] << std::endl 03327 << " shared ids: " << t[SHARED_SET_IDS] << std::endl 03328 << " shared data: " << t[SHARED_SET_CONTENTS] << std::endl 03329 << " set offsets: " << t[SET_OFFSET_TIME] << std::endl 03330 << " create tags: " << t[CREATE_TAG_TIME] << std::endl 03331 << " coordinates: " << t[COORD_TIME] << std::endl 03332 << " connectivity: " << t[CONN_TIME] << std::endl 03333 << " sets: " << t[SET_TIME] << std::endl 03334 << " set descrip: " << t[SET_META] << std::endl 03335 << " set content: " << t[SET_CONTENT] << std::endl 03336 << " set parent: " << t[SET_PARENT] << std::endl 03337 << " set child: " << t[SET_CHILD] << std::endl 03338 << " adjacencies: " << t[ADJ_TIME] << std::endl 03339 << " tags: " << t[TAG_TIME] << std::endl 03340 << " dense data: " << t[DENSE_TAG_TIME] << std::endl 03341 << " sparse data: " << t[SPARSE_TAG_TIME] << std::endl 03342 << " var-len data: " << t[VARLEN_TAG_TIME] << std::endl; 03343 } 03344 03345 } // namespace moab