1 #undef DEBUG
2 #undef TIME_DEBUG
3
4 #include <cstdarg>
5 #include <ctime>
6 #include <cstdlib>
7
8 #include <cstring>
9 #include <cassert>
10
11 #include <vector>
12 #include <set>
13 #include <map>
14 #include <utility>
15 #include <iostream>
16 #include <sstream>
17 #include <string>
18
19 #include "moab/Interface.hpp"
20 #include "Internals.hpp"
21 #include "MBTagConventions.hpp"
22 #include "MBParallelConventions.h"
23 #include "moab/ParallelComm.hpp"
24 #include "moab/CN.hpp"
25 #include "moab/Range.hpp"
26 #include "moab/CpuTimer.hpp"
27
28 #include "WriteHDF5Parallel.hpp"
29
30 #ifndef MOAB_HAVE_HDF5
31 #error Attempt to compile WriteHDF5Parallel with HDF5 support disabled
32 #endif
33
34 #include <H5Tpublic.h>
35 #include <H5Ppublic.h>
36 #include <H5FDmpi.h>
37 #include <H5FDmpio.h>
38
39 #include "mhdf.h"
40
41 #include "IODebugTrack.hpp"
42 #include "moab/FileOptions.hpp"
43
44 namespace
45 {
46 template < bool Condition >
47 struct STATIC_ASSERTION;
48 template <>
49 struct STATIC_ASSERTION< true >
50 {
51 };
52 }
53
54 #define PP_CAT_( a, b ) a##b
55 #define PP_CAT( a, b ) PP_CAT_( a, b )
56 #define STATIC_ASSERT( Condition ) \
57 enum \
58 { \
59 PP_CAT( dummy, __LINE__ ) = sizeof( ::STATIC_ASSERTION< (bool)( Condition ) > ) \
60 }
61
62 namespace moab
63 {
64
65 #ifndef _WIN32
66
67 STATIC_ASSERT( sizeof( unsigned long ) >= sizeof( EntityHandle ) );
68
69
70 STATIC_ASSERT( sizeof( unsigned long ) >= sizeof( WriteHDF5::wid_t ) );
71 #endif
72
73
74
75 static inline ErrorCode error( ErrorCode rval )
76 {
77 return rval;
78 }
79
80 const char* mpi_err_str( int errorcode )
81 {
82 static char buffer[2048];
83 int len = sizeof( buffer );
84 MPI_Error_string( errorcode, buffer, &len );
85 buffer[std::min( (size_t)len, sizeof( buffer ) - 1 )] = '\0';
86 return buffer;
87 }
88
89 #define MPI_FAILURE_MSG( A ) \
90 "MPI Failure at " __FILE__ ":%d : (Code %d) %s\n", __LINE__, (int)( A ), mpi_err_str( ( A ) )
91
92 #define CHECK_MPI( A ) \
93 do \
94 { \
95 if( MPI_SUCCESS != ( A ) ) \
96 { \
97 MB_SET_ERR_CONT( "MPI Failure : (Code " << (int)( A ) << ") " << mpi_err_str( ( A ) ) ); \
98 dbgOut.printf( 1, MPI_FAILURE_MSG( ( A ) ) ); \
99 return error( MB_FAILURE ); \
100 } \
101 } while( false )
102
103 #define MB_FAILURE_MSG( A ) "MOAB_Failure at " __FILE__ ":%d : %s (%d)\n", __LINE__, ErrorCodeStr[( A )], (int)( A )
104
105 #define CHECK_MB( A ) \
106 do \
107 { \
108 if( MB_SUCCESS != ( A ) ) \
109 { \
110 MB_SET_ERR_CONT( "MOAB Failure : " << ErrorCodeStr[( A )] ); \
111 dbgOut.printf( 1, MB_FAILURE_MSG( ( A ) ) ); \
112 return error( A ); \
113 } \
114 } while( false )
115
116 #define HDF_FAILURE_MSG( A ) "MHDF Failure at " __FILE__ ":%d : %s\n", __LINE__, mhdf_message( &( A ) )
117
118 #define CHECK_HDF( A ) \
119 do \
120 { \
121 if( mhdf_isError( &( A ) ) ) \
122 { \
123 MB_SET_ERR_CONT( "MHDF Failure : " << mhdf_message( &( A ) ) ); \
124 dbgOut.printf( 1, HDF_FAILURE_MSG( ( A ) ) ); \
125 return error( MB_FAILURE ); \
126 } \
127 } while( false )
128
129 #define CHECK_HDFN( A ) \
130 do \
131 { \
132 if( mhdf_isError( &( A ) ) ) \
133 { \
134 MB_SET_ERR_CONT( "MHDF Failure : " << mhdf_message( &( A ) ) ); \
135 return error( MB_FAILURE ); \
136 } \
137 } while( false )
138
139 #ifdef VALGRIND
140 #include <valgrind/memcheck.h>
141
142 template < typename T >
143 inline void VALGRIND_MAKE_VEC_UNDEFINED( std::vector< T >& v )
144 {
145 if( v.size() )
146 {
147 }
148 (void)VALGRIND_MAKE_MEM_UNDEFINED( &v[0], v.size() * sizeof( T ) );
149 }
150
151 #else
152 #ifndef VALGRIND_CHECK_MEM_IS_DEFINED
153 #define VALGRIND_CHECK_MEM_IS_DEFINED( a, b ) ( (void)0 )
154 #endif
155 #ifndef VALGRIND_CHECK_MEM_IS_ADDRESSABLE
156 #define VALGRIND_CHECK_MEM_IS_ADDRESSABLE( a, b ) ( (void)0 )
157 #endif
158 #ifndef VALGRIND_MAKE_MEM_UNDEFINED
159 #define VALGRIND_MAKE_MEM_UNDEFINED( a, b ) ( (void)0 )
160 #endif
161
162 template < typename T >
163 inline void VALGRIND_MAKE_VEC_UNDEFINED( std::vector< T >& )
164 {
165
166 }
167
168 #endif
169
170 #ifndef NDEBUG
171 #define START_SERIAL \
172 for( unsigned _x = 0; _x < myPcomm->proc_config().proc_size(); ++_x ) \
173 { \
174 MPI_Barrier( myPcomm->proc_config().proc_comm() ); \
175 if( _x != myPcomm->proc_config().proc_rank() ) continue
176 #define END_SERIAL \
177 } \
178 MPI_Barrier( myPcomm->proc_config().proc_comm() )
179 #else
180 #define START_SERIAL
181 #define END_SERIAL
182 #endif
183
184 static int my_Gatherv( void* sendbuf,
185 int sendcount,
186 MPI_Datatype sendtype,
187 std::vector< unsigned char >& recvbuf,
188 std::vector< int >& recvcounts,
189 int root,
190 MPI_Comm comm )
191 {
192 int nproc, rank, bytes, err;
193 MPI_Comm_size( comm, &nproc );
194 MPI_Comm_rank( comm, &rank );
195 MPI_Type_size( sendtype, &bytes );
196
197 recvcounts.resize( rank == root ? nproc : 0 );
198 err = MPI_Gather( &sendcount, 1, MPI_INT, &recvcounts[0], 1, MPI_INT, root, comm );
199 if( MPI_SUCCESS != err ) return err;
200
201 std::vector< int > disp( recvcounts.size() );
202 if( root == rank )
203 {
204 disp[0] = 0;
205 for( int i = 1; i < nproc; ++i )
206 disp[i] = disp[i - 1] + recvcounts[i - 1];
207 recvbuf.resize( bytes * ( disp.back() + recvcounts.back() ) );
208 }
209
210 return MPI_Gatherv( sendbuf, sendcount, sendtype, &recvbuf[0], &recvcounts[0], &disp[0], sendtype, root, comm );
211 }
212
213 static void print_type_sets( Interface* iFace, DebugOutput* str, Range& sets )
214 {
215 const unsigned VB = 2;
216 if( str->get_verbosity() < VB ) return;
217
218 Tag gid, did, bid, sid, nid;
219 gid = iFace->globalId_tag();
220 iFace->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, did );
221 iFace->tag_get_handle( MATERIAL_SET_TAG_NAME, 1, MB_TYPE_INTEGER, bid );
222 iFace->tag_get_handle( DIRICHLET_SET_TAG_NAME, 1, MB_TYPE_INTEGER, nid );
223 iFace->tag_get_handle( NEUMANN_SET_TAG_NAME, 1, MB_TYPE_INTEGER, sid );
224 Range typesets[10];
225 const char* typenames[] = { "Block ", "Sideset ", "NodeSet", "Vertex", "Curve",
226 "Surface", "Volume", "Body", "Other" };
227 for( Range::iterator riter = sets.begin(); riter != sets.end(); ++riter )
228 {
229 unsigned dim, id;
230 if( MB_SUCCESS == iFace->tag_get_data( bid, &*riter, 1, &id ) )
231 dim = 0;
232 else if( MB_SUCCESS == iFace->tag_get_data( sid, &*riter, 1, &id ) )
233 dim = 1;
234 else if( MB_SUCCESS == iFace->tag_get_data( nid, &*riter, 1, &id ) )
235 dim = 2;
236 else if( MB_SUCCESS == iFace->tag_get_data( did, &*riter, 1, &dim ) )
237 {
238 id = 0;
239 iFace->tag_get_data( gid, &*riter, 1, &id );
240 dim += 3;
241 }
242 else
243 {
244 id = *riter;
245 dim = 9;
246 }
247
248
249 typesets[dim].insert( id );
250
251 }
252 for( int ii = 0; ii < 9; ++ii )
253 {
254 char tmp[64];
255 snprintf( tmp, 64, "%s (%lu) ", typenames[ii], (unsigned long)typesets[ii].size() );
256 str->print( VB, tmp, typesets[ii] );
257 }
258 str->printf( VB, "Total: %lu\n", (unsigned long)sets.size() );
259 }
260
261 #define debug_barrier() debug_barrier_line( __LINE__ )
262
263 void WriteHDF5Parallel::debug_barrier_line( int lineno )
264 {
265 const unsigned threshold = 2;
266 static unsigned long count = 0;
267 if( dbgOut.get_verbosity() >= threshold && myPcomm )
268 {
269 dbgOut.printf( threshold, "*********** Debug Barrier %lu (@%d)***********\n", ++count, lineno );
270 MPI_Barrier( myPcomm->proc_config().proc_comm() );
271 }
272 }
273
274 WriterIface* WriteHDF5Parallel::factory( Interface* iface )
275 {
276 return new WriteHDF5Parallel( iface );
277 }
278
279 WriteHDF5Parallel::WriteHDF5Parallel( Interface* iface )
280 : WriteHDF5( iface ), myPcomm( NULL ), pcommAllocated( false ), hslabOp( H5S_SELECT_OR )
281 {
282 }
283
284 WriteHDF5Parallel::~WriteHDF5Parallel()
285 {
286 if( pcommAllocated && myPcomm ) delete myPcomm;
287 }
288
289
290
291
292
293
294
295 ErrorCode WriteHDF5Parallel::gather_interface_meshes( Range& nonowned )
296 {
297 ErrorCode result;
298
299
300 dbgOut.print( 3, "Pre-interface mesh:\n" );
301 dbgOut.print( 3, nodeSet.range );
302 for( std::list< ExportSet >::iterator eiter = exportList.begin(); eiter != exportList.end(); ++eiter )
303 dbgOut.print( 3, eiter->range );
304 dbgOut.print( 3, setSet.range );
305
306
307
308
309 nonowned.clear();
310 result = myPcomm->filter_pstatus( nodeSet.range, PSTATUS_NOT_OWNED, PSTATUS_AND, -1, &nonowned );
311 if( MB_SUCCESS != result ) return error( result );
312 nodeSet.range = subtract( nodeSet.range, nonowned );
313
314 for( std::list< ExportSet >::iterator eiter = exportList.begin(); eiter != exportList.end(); ++eiter )
315 {
316 Range tmpset;
317 result = myPcomm->filter_pstatus( eiter->range, PSTATUS_NOT_OWNED, PSTATUS_AND, -1, &tmpset );
318 if( MB_SUCCESS != result ) return error( result );
319 eiter->range = subtract( eiter->range, tmpset );
320 nonowned.merge( tmpset );
321 }
322
323 dbgOut.print( 3, "Post-interface mesh:\n" );
324 dbgOut.print( 3, nodeSet.range );
325 for( std::list< ExportSet >::iterator eiter = exportList.begin(); eiter != exportList.end(); ++eiter )
326 dbgOut.print( 3, eiter->range );
327 dbgOut.print( 3, setSet.range );
328
329
330
331 return MB_SUCCESS;
332 }
333
334 ErrorCode WriteHDF5Parallel::parallel_create_file( const char* filename,
335 bool overwrite,
336 const std::vector< std::string >& qa_records,
337 const FileOptions& opts,
338 const Tag* user_tag_list,
339 int user_tag_count,
340 int dimension,
341 double* times )
342 {
343 ErrorCode rval;
344 mhdf_Status status;
345
346 int pcomm_no = 0;
347 opts.get_int_option( "PARALLEL_COMM", pcomm_no );
348
349 myPcomm = ParallelComm::get_pcomm( iFace, pcomm_no );
350 if( 0 == myPcomm )
351 {
352 myPcomm = new ParallelComm( iFace, MPI_COMM_WORLD );
353 pcommAllocated = true;
354 }
355
356 MPI_Info info = MPI_INFO_NULL;
357 std::string cb_size;
358 rval = opts.get_str_option( "CB_BUFFER_SIZE", cb_size );
359 if( MB_SUCCESS == rval )
360 {
361 MPI_Info_create( &info );
362 MPI_Info_set( info, const_cast< char* >( "cb_buffer_size" ), const_cast< char* >( cb_size.c_str() ) );
363 }
364
365 dbgOut.set_rank( myPcomm->proc_config().proc_rank() );
366 dbgOut.limit_output_to_first_N_procs( 32 );
367 Range nonlocal;
368 debug_barrier();
369 dbgOut.tprint( 1, "Gathering interface meshes\n" );
370 rval = gather_interface_meshes( nonlocal );
371 if( MB_SUCCESS != rval ) return error( rval );
372
373
374
375
376
377
378
379
380
381 debug_barrier();
382 if( myPcomm->proc_config().proc_rank() == 0 )
383 {
384 dbgOut.tprintf( 1, "Creating file: %s\n", filename );
385
386
387 const char* type_names[MBMAXTYPE];
388 memset( type_names, 0, MBMAXTYPE * sizeof( char* ) );
389 for( EntityType i = MBEDGE; i < MBENTITYSET; ++i )
390 type_names[i] = CN::EntityTypeName( i );
391
392 dbgOut.tprint( 1, "call mhdf_createFile\n" );
393 filePtr = mhdf_createFile( filename, overwrite, type_names, MBMAXTYPE, id_type, &status );
394 if( !filePtr )
395 {
396 MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
397 }
398
399 dbgOut.tprint( 1, "call write_qa\n" );
400 rval = write_qa( qa_records );
401 if( MB_SUCCESS != rval ) return error( rval );
402 }
403
404
405 CpuTimer timer;
406 debug_barrier();
407 dbgOut.tprint( 1, "creating node table\n" );
408 topState.start( "creating node table" );
409 rval = create_node_table( dimension );
410 topState.end( rval );
411 if( MB_SUCCESS != rval ) return error( rval );
412 if( times ) times[CREATE_NODE_TIME] = timer.time_elapsed();
413
414
415
416 debug_barrier();
417 dbgOut.tprint( 1, "negotiating element types\n" );
418 topState.start( "negotiating element types" );
419 rval = negotiate_type_list();
420 topState.end( rval );
421 if( MB_SUCCESS != rval ) return error( rval );
422 if( times ) times[NEGOTIATE_TYPES_TIME] = timer.time_elapsed();
423 dbgOut.tprint( 1, "creating element table\n" );
424 topState.start( "creating element tables" );
425 rval = create_element_tables();
426 topState.end( rval );
427 if( MB_SUCCESS != rval ) return error( rval );
428 if( times ) times[CREATE_ELEM_TIME] = timer.time_elapsed();
429
430
431
432 debug_barrier();
433 dbgOut.tprint( 1, "communicating file ids\n" );
434 topState.start( "communicating file ids" );
435 rval = exchange_file_ids( nonlocal );
436 topState.end( rval );
437 if( MB_SUCCESS != rval ) return error( rval );
438 if( times ) times[FILEID_EXCHANGE_TIME] = timer.time_elapsed();
439
440
441
442 debug_barrier();
443 dbgOut.tprint( 1, "creating meshset table\n" );
444 topState.start( "creating meshset tables" );
445 rval = create_meshset_tables( times );
446 topState.end( rval );
447 if( MB_SUCCESS != rval ) return error( rval );
448 if( times ) times[CREATE_SET_TIME] = timer.time_elapsed();
449
450
451
452 debug_barrier();
453 dbgOut.tprint( 1, "creating adjacency table\n" );
454 topState.start( "creating adjacency tables" );
455 rval = create_adjacency_tables();
456 topState.end( rval );
457 if( MB_SUCCESS != rval ) return error( rval );
458 if( times ) times[CREATE_ADJ_TIME] = timer.time_elapsed();
459
460
461
462 debug_barrier();
463 dbgOut.tprint( 1, "creating tag tables\n" );
464 topState.start( "creating tag tables" );
465 rval = gather_tags( user_tag_list, user_tag_count );
466 if( MB_SUCCESS != rval ) return error( rval );
467 rval = create_tag_tables();
468 topState.end( rval );
469 if( MB_SUCCESS != rval ) return error( rval );
470 if( times ) times[CREATE_TAG_TIME] = timer.time_elapsed();
471
472
473
474 if( 0 == myPcomm->proc_config().proc_rank() ) mhdf_closeFile( filePtr, &status );
475
476 MPI_Barrier( myPcomm->proc_config().proc_comm() );
477 dbgOut.tprint( 1, "(re)opening file in parallel mode\n" );
478 unsigned long junk;
479 hid_t hdf_opt = H5Pcreate( H5P_FILE_ACCESS );
480 H5Pset_fapl_mpio( hdf_opt, myPcomm->proc_config().proc_comm(), info );
481 filePtr = mhdf_openFileWithOpt( filename, 1, &junk, id_type, hdf_opt, &status );
482 H5Pclose( hdf_opt );
483 if( !filePtr )
484 {
485 MB_SET_ERR( MB_FAILURE, mhdf_message( &status ) );
486 }
487
488 if( collectiveIO )
489 {
490 dbgOut.print( 1, "USING COLLECTIVE IO\n" );
491 writeProp = H5Pcreate( H5P_DATASET_XFER );
492 H5Pset_dxpl_mpio( writeProp, H5FD_MPIO_COLLECTIVE );
493 }
494
495
496 if( MB_SUCCESS != opts.get_null_option( "HYPERSLAB_OR" ) &&
497 ( MB_SUCCESS == opts.get_null_option( "HYPERSLAB_APPEND" ) || HDF5_can_append_hyperslabs() ) )
498 {
499 dbgOut.print( 1, "HDF5 library supports H5Sselect_hyperlsab with H5S_SELECT_APPEND\n" );
500 hslabOp = H5S_SELECT_APPEND;
501 }
502
503 dbgOut.tprint( 1, "Exiting parallel_create_file\n" );
504 return MB_SUCCESS;
505 }
506
507 class TagNameCompare
508 {
509 Interface* iFace;
510 std::string name1, name2;
511
512 public:
513 TagNameCompare( Interface* iface ) : iFace( iface ) {}
514 bool operator()( const WriteHDF5::TagDesc& t1, const WriteHDF5::TagDesc& t2 );
515 };
516
517 bool TagNameCompare::operator()( const WriteHDF5::TagDesc& t1, const WriteHDF5::TagDesc& t2 )
518 {
519 iFace->tag_get_name( t1.tag_id, name1 );
520 iFace->tag_get_name( t2.tag_id, name2 );
521 return name1 < name2;
522 }
523
524 struct serial_tag_data
525 {
526 TagType storage;
527 DataType type;
528 int size;
529 int name_len;
530 int def_val_len;
531 char name[sizeof( unsigned long )];
532
533 static size_t pad( size_t len )
534 {
535 if( len % sizeof( unsigned long ) )
536 return len + sizeof( unsigned long ) - len % sizeof( unsigned long );
537 else
538 return len;
539 }
540
541 static size_t def_val_bytes( int def_val_len, DataType type )
542 {
543 switch( type )
544 {
545 case MB_TYPE_BIT:
546 return def_val_len ? 1 : 0;
547 case MB_TYPE_OPAQUE:
548 return def_val_len;
549 case MB_TYPE_INTEGER:
550 return def_val_len * sizeof( int );
551 case MB_TYPE_DOUBLE:
552 return def_val_len * sizeof( double );
553 case MB_TYPE_HANDLE:
554 return def_val_len * sizeof( EntityHandle );
555 }
556 return 0;
557 }
558
559 static size_t len( int name_len, int def_val_len, DataType type )
560 {
561 return sizeof( serial_tag_data ) + pad( name_len + def_val_bytes( def_val_len, type ) ) -
562 sizeof( unsigned long );
563 }
564 size_t len() const
565 {
566 return len( name_len, def_val_len, type );
567 }
568 void* default_value()
569 {
570 return def_val_len ? name + name_len : 0;
571 }
572 const void* default_value() const
573 {
574 return const_cast< serial_tag_data* >( this )->default_value();
575 }
576 void set_default_value( const void* val )
577 {
578 memcpy( default_value(), val, def_val_bytes( def_val_len, type ) );
579 }
580 };
581
582 ErrorCode WriteHDF5Parallel::append_serial_tag_data( std::vector< unsigned char >& buffer,
583 const WriteHDF5::TagDesc& tag )
584 {
585 ErrorCode rval;
586
587 std::string name;
588 rval = iFace->tag_get_name( tag.tag_id, name );
589 if( MB_SUCCESS != rval ) return error( rval );
590
591
592 size_t name_len = name.size() + 1;
593 if( name_len == 1 ) return MB_SUCCESS;
594
595 DataType data_type;
596 rval = iFace->tag_get_data_type( tag.tag_id, data_type );
597 if( MB_SUCCESS != rval ) return error( rval );
598
599
600 int def_val_len;
601 const void* def_val;
602 if( MB_SUCCESS != iFace->tag_get_default_value( tag.tag_id, def_val, def_val_len ) )
603 {
604 def_val_len = 0;
605 def_val = 0;
606 }
607
608
609 size_t init_size = buffer.size();
610 buffer.resize( init_size + serial_tag_data::len( name_len, def_val_len, data_type ) );
611 serial_tag_data* ptr = reinterpret_cast< serial_tag_data* >( &buffer[init_size] );
612
613
614 rval = iFace->tag_get_type( tag.tag_id, ptr->storage );
615 if( MB_SUCCESS != rval ) return error( rval );
616 ptr->type = data_type;
617 rval = iFace->tag_get_length( tag.tag_id, ptr->size );
618 if( MB_VARIABLE_DATA_LENGTH == rval )
619 ptr->size = MB_VARIABLE_LENGTH;
620 else if( MB_SUCCESS != rval )
621 return error( rval );
622 ptr->name_len = name_len;
623 Range range;
624 memset( ptr->name, 0, ptr->name_len );
625 memcpy( ptr->name, name.data(), name.size() );
626 ptr->def_val_len = def_val_len;
627 ptr->set_default_value( def_val );
628
629 return MB_SUCCESS;
630 }
631
632 ErrorCode WriteHDF5Parallel::check_serial_tag_data( const std::vector< unsigned char >& buffer,
633 std::vector< TagDesc* >* missing,
634 std::vector< TagDesc* >* newlist )
635 {
636 ErrorCode rval;
637
638
639 std::list< TagDesc >::iterator tag_iter;
640 if( missing )
641 for( tag_iter = tagList.begin(); tag_iter != tagList.end(); ++tag_iter )
642 tag_iter->write_sparse = true;
643
644
645
646
647 std::set< TagDesc* > newset;
648
649
650
651
652 std::vector< unsigned char >::const_iterator diter = buffer.begin();
653 tag_iter = tagList.begin();
654 while( diter < buffer.end() )
655 {
656
657 const serial_tag_data* ptr = reinterpret_cast< const serial_tag_data* >( &*diter );
658
659
660 std::string name( ptr->name );
661 std::string n;
662 iFace->tag_get_name( tag_iter->tag_id, n );
663 if( n > name )
664 {
665 tag_iter = tagList.begin();
666 }
667 iFace->tag_get_name( tag_iter->tag_id, n );
668 while( n < name )
669 {
670 ++tag_iter;
671 if( tag_iter == tagList.end() ) break;
672 iFace->tag_get_name( tag_iter->tag_id, n );
673 }
674 if( tag_iter == tagList.end() || n != name )
675 {
676 TagDesc newtag;
677
678 if( ptr->size == MB_VARIABLE_LENGTH )
679 rval = iFace->tag_get_handle( name.c_str(), ptr->def_val_len, ptr->type, newtag.tag_id,
680 MB_TAG_VARLEN | MB_TAG_CREAT | ptr->storage, ptr->default_value() );
681 else
682 rval = iFace->tag_get_handle( name.c_str(), ptr->size, ptr->type, newtag.tag_id,
683 MB_TAG_CREAT | ptr->storage, ptr->default_value() );
684 if( MB_SUCCESS != rval ) return error( rval );
685
686 newtag.sparse_offset = 0;
687 newtag.var_data_offset = 0;
688 newtag.write_sparse = false;
689 newtag.max_num_ents = 0;
690 newtag.max_num_vals = 0;
691
692 tag_iter = tagList.insert( tag_iter, newtag );
693 if( newlist ) newset.insert( &*tag_iter );
694 }
695 else
696 {
697 DataType type;
698 iFace->tag_get_data_type( tag_iter->tag_id, type );
699 if( type != ptr->type )
700 {
701 MB_SET_ERR( MB_FAILURE, "Processes have inconsistent data type for tag \"" << name << "\"" );
702 }
703 int size;
704 iFace->tag_get_length( tag_iter->tag_id, size );
705 if( size != ptr->size )
706 {
707 MB_SET_ERR( MB_FAILURE, "Processes have inconsistent size for tag \"" << name << "\"" );
708 }
709 tag_iter->write_sparse = false;
710 }
711
712
713 diter += ptr->len();
714 }
715
716
717 if( missing )
718 {
719 for( tag_iter = tagList.begin(); tag_iter != tagList.end(); ++tag_iter )
720 {
721 if( tag_iter->write_sparse )
722 {
723 tag_iter->write_sparse = false;
724 missing->push_back( &*tag_iter );
725 }
726 }
727 }
728
729
730 if( newlist )
731 {
732 for( tag_iter = tagList.begin(); tag_iter != tagList.end(); ++tag_iter )
733 if( newset.find( &*tag_iter ) != newset.end() ) newlist->push_back( &*tag_iter );
734 }
735
736 return MB_SUCCESS;
737 }
738
739 static void set_bit( int position, unsigned char* bytes )
740 {
741 int byte = position / 8;
742 int bit = position % 8;
743 bytes[byte] |= ( ( (unsigned char)1 ) << bit );
744 }
745
746 static bool get_bit( int position, const unsigned char* bytes )
747 {
748 int byte = position / 8;
749 int bit = position % 8;
750 return 0 != ( bytes[byte] & ( ( (unsigned char)1 ) << bit ) );
751 }
752
753 ErrorCode WriteHDF5Parallel::create_tag_tables()
754 {
755 std::list< TagDesc >::iterator tag_iter;
756 ErrorCode rval;
757 int err;
758 const int rank = myPcomm->proc_config().proc_rank();
759 const MPI_Comm comm = myPcomm->proc_config().proc_comm();
760
761 subState.start( "negotiating tag list" );
762
763 dbgOut.tprint( 1, "communicating tag metadata\n" );
764
765 dbgOut.printf( 2, "Exchanging tag data for %d tags.\n", (int)tagList.size() );
766
767
768 tagList.sort( TagNameCompare( iFace ) );
769
770
771
772
773 std::vector< unsigned char > tag_buffer;
774 for( tag_iter = tagList.begin(); tag_iter != tagList.end(); ++tag_iter )
775 {
776 rval = append_serial_tag_data( tag_buffer, *tag_iter );
777 CHECK_MB( rval );
778 }
779
780
781 unsigned long size = tag_buffer.size();
782 err = MPI_Bcast( &size, 1, MPI_UNSIGNED_LONG, 0, comm );
783 CHECK_MPI( err );
784 tag_buffer.resize( size );
785 err = MPI_Bcast( &tag_buffer[0], size, MPI_UNSIGNED_CHAR, 0, comm );
786 CHECK_MPI( err );
787
788
789 std::vector< TagDesc* > missing;
790 rval = check_serial_tag_data( tag_buffer, &missing, 0 );
791 CHECK_MB( rval );
792
793
794 int code, lcode = ( MB_SUCCESS != rval ) ? rval + 2 : missing.empty() ? 0 : 1;
795 err = MPI_Allreduce( &lcode, &code, 1, MPI_INT, MPI_MAX, comm );
796 CHECK_MPI( err );
797 if( code > 1 )
798 {
799 MB_SET_ERR_CONT( "Inconsistent tag definitions between procs" );
800 return error( (ErrorCode)( code - 2 ) );
801 }
802
803
804 if( code )
805 {
806 dbgOut.print( 1, "Not all procs had same tag definitions, negotiating...\n" );
807
808
809 tag_buffer.clear();
810 for( size_t i = 0; i < missing.size(); ++i )
811 {
812 rval = append_serial_tag_data( tag_buffer, *missing[i] );
813 CHECK_MB( rval );
814 }
815
816
817 std::vector< int > junk;
818 assert( rank || tag_buffer.empty() );
819 err = my_Gatherv( &tag_buffer[0], tag_buffer.size(), MPI_UNSIGNED_CHAR, tag_buffer, junk, 0, comm );
820 CHECK_MPI( err );
821
822
823 rval = MB_SUCCESS;
824 if( 0 == rank )
825 {
826
827 std::vector< TagDesc* > newlist;
828 rval = check_serial_tag_data( tag_buffer, 0, &newlist );
829 tag_buffer.clear();
830
831 for( size_t i = 0; MB_SUCCESS == rval && i != newlist.size(); ++i )
832 {
833 rval = append_serial_tag_data( tag_buffer, *newlist[i] );
834 CHECK_MB( rval );
835 }
836 }
837
838
839 long this_size = tag_buffer.size();
840 if( MB_SUCCESS != rval ) this_size = -rval;
841 err = MPI_Bcast( &this_size, 1, MPI_LONG, 0, comm );
842 CHECK_MPI( err );
843 if( this_size < 0 )
844 {
845 MB_SET_ERR_CONT( "Inconsistent tag definitions between procs" );
846 return error( (ErrorCode)-this_size );
847 }
848 tag_buffer.resize( this_size );
849 err = MPI_Bcast( &tag_buffer[0], this_size, MPI_UNSIGNED_CHAR, 0, comm );
850 CHECK_MPI( err );
851
852
853 rval = check_serial_tag_data( tag_buffer, 0, 0 );
854 CHECK_MB( rval );
855 }
856
857 subState.end();
858 subState.start( "negotiate which element/tag combinations are dense" );
859
860
861
862
863
864
865
866
867
868
869 const int bytes_per_tag = ( exportList.size() + 9 ) / 8;
870 std::vector< unsigned char > data( bytes_per_tag * tagList.size(), 0 );
871 std::vector< unsigned char > recv( data.size(), 0 );
872 unsigned char* iter = &data[0];
873 if( writeTagDense && !data.empty() )
874 {
875 for( tag_iter = tagList.begin(); tag_iter != tagList.end(); ++tag_iter, iter += bytes_per_tag )
876 {
877
878 Range tagged;
879 rval = get_sparse_tagged_entities( *tag_iter, tagged );
880 CHECK_MB( rval );
881
882 int s;
883 if( MB_VARIABLE_DATA_LENGTH == iFace->tag_get_length( tag_iter->tag_id, s ) ) continue;
884
885 std::string n;
886 iFace->tag_get_name( tag_iter->tag_id,
887 n );
888
889
890
891
892
893 bool prefer_dense = false;
894 TagType type;
895 rval = iFace->tag_get_type( tag_iter->tag_id, type );
896 CHECK_MB( rval );
897 if( MB_TAG_DENSE == type )
898 {
899 const void* defval = 0;
900 rval = iFace->tag_get_default_value( tag_iter->tag_id, defval, s );
901 if( MB_SUCCESS == rval ) prefer_dense = true;
902 }
903
904 int i = 0;
905 if( check_dense_format_tag( nodeSet, tagged, prefer_dense ) )
906 {
907 set_bit( i, iter );
908 dbgOut.printf( 2, "Can write dense data for \"%s\"/Nodes\n", n.c_str() );
909 }
910 std::list< ExportSet >::const_iterator ex_iter = exportList.begin();
911 for( ++i; ex_iter != exportList.end(); ++i, ++ex_iter )
912 {
913
914
915
916 if( ( prefer_dense && ex_iter->range.empty() ) ||
917 check_dense_format_tag( *ex_iter, tagged, prefer_dense ) )
918 {
919 set_bit( i, iter );
920 dbgOut.printf( 2, "Can write dense data for \"%s\"/%s\n", n.c_str(), ex_iter->name() );
921 }
922 }
923 if( check_dense_format_tag( setSet, tagged, prefer_dense ) )
924 {
925 set_bit( i, iter );
926 dbgOut.printf( 2, "Can write dense data for \"%s\"/Sets\n", n.c_str() );
927 }
928 }
929
930
931
932 err = MPI_Allreduce( &data[0], &recv[0], data.size(), MPI_UNSIGNED_CHAR, MPI_BAND,
933 myPcomm->proc_config().proc_comm() );
934 CHECK_MPI( err );
935 }
936
937
938
939
940
941 std::vector< long > counts;
942
943
944 iter = &recv[0];
945 const unsigned char* iter2 = &data[0];
946 for( tag_iter = tagList.begin(); tag_iter != tagList.end();
947 ++tag_iter, iter += bytes_per_tag, iter2 += bytes_per_tag )
948 {
949
950 Range tagged;
951 rval = get_sparse_tagged_entities( *tag_iter, tagged );
952 CHECK_MB( rval );
953
954 std::string n;
955 iFace->tag_get_name( tag_iter->tag_id, n );
956
957 int i = 0;
958 if( get_bit( i, iter ) )
959 {
960 assert( get_bit( i, iter2 ) );
961 tag_iter->dense_list.push_back( nodeSet );
962 tagged -= nodeSet.range;
963 dbgOut.printf( 2, "Will write dense data for \"%s\"/Nodes\n", n.c_str() );
964 }
965 std::list< ExportSet >::const_iterator ex_iter = exportList.begin();
966 for( ++i; ex_iter != exportList.end(); ++i, ++ex_iter )
967 {
968 if( get_bit( i, iter ) )
969 {
970 assert( get_bit( i, iter2 ) );
971 tag_iter->dense_list.push_back( *ex_iter );
972 dbgOut.printf( 2, "WIll write dense data for \"%s\"/%s\n", n.c_str(), ex_iter->name() );
973 tagged -= ex_iter->range;
974 }
975 }
976 if( get_bit( i, iter ) )
977 {
978 assert( get_bit( i, iter2 ) );
979 tag_iter->dense_list.push_back( setSet );
980 dbgOut.printf( 2, "Will write dense data for \"%s\"/Sets\n", n.c_str() );
981 tagged -= setSet.range;
982 }
983
984 counts.push_back( tagged.size() );
985
986 int s;
987 if( MB_VARIABLE_DATA_LENGTH == iFace->tag_get_length( tag_iter->tag_id, s ) )
988 {
989 unsigned long data_len;
990 rval = get_tag_data_length( *tag_iter, tagged, data_len );
991 CHECK_MB( rval );
992 counts.push_back( data_len );
993 }
994 }
995
996 subState.end();
997 subState.start( "Negotiate offsets for sparse tag info" );
998
999 std::vector< long > offsets( counts.size() ), maxima( counts.size() ), totals( counts.size() );
1000 rval = create_dataset( counts.size(), &counts[0], &offsets[0], &maxima[0], &totals[0] );
1001 CHECK_MB( rval );
1002
1003
1004 size_t idx = 0;
1005 for( tag_iter = tagList.begin(); tag_iter != tagList.end(); ++tag_iter, ++idx )
1006 {
1007 assert( idx < counts.size() );
1008 tag_iter->sparse_offset = offsets[idx];
1009 tag_iter->max_num_ents = maxima[idx];
1010 tag_iter->write_sparse = ( 0 != totals[idx] );
1011 int s;
1012 if( MB_VARIABLE_DATA_LENGTH == iFace->tag_get_length( tag_iter->tag_id, s ) )
1013 {
1014 ++idx;
1015 assert( idx < counts.size() );
1016 tag_iter->var_data_offset = offsets[idx];
1017 tag_iter->max_num_vals = maxima[idx];
1018 }
1019 else
1020 {
1021 tag_iter->var_data_offset = 0;
1022 tag_iter->max_num_vals = 0;
1023 }
1024 }
1025
1026 subState.end();
1027
1028
1029 if( 0 == myPcomm->proc_config().proc_rank() )
1030 {
1031 size_t iidx = 0;
1032 for( tag_iter = tagList.begin(); tag_iter != tagList.end(); ++tag_iter, ++iidx )
1033 {
1034 assert( iidx < totals.size() );
1035 unsigned long num_ents = totals[iidx];
1036 unsigned long num_val = 0;
1037 int s;
1038 if( MB_VARIABLE_DATA_LENGTH == iFace->tag_get_length( tag_iter->tag_id, s ) )
1039 {
1040 ++iidx;
1041 assert( iidx < totals.size() );
1042 num_val = totals[iidx];
1043 }
1044 dbgOut.printf( 2, "Writing tag description for tag 0x%lx with %lu values\n",
1045 (unsigned long)tag_iter->tag_id, num_val ? num_val : num_ents );
1046
1047 rval = create_tag( *tag_iter, num_ents, num_val );
1048 if( MB_SUCCESS != rval ) return error( rval );
1049 }
1050 }
1051
1052 if( dbgOut.get_verbosity() > 1 )
1053 {
1054 dbgOut.printf( 2, "Tags: %12s %8s %8s %8s %8s %8s\n", "Name", "Count", "Offset", "Var Off", "Max Ent",
1055 "Handle" );
1056
1057 for( tag_iter = tagList.begin(); tag_iter != tagList.end(); ++tag_iter )
1058 {
1059 std::string name;
1060 iFace->tag_get_name( tag_iter->tag_id, name );
1061 size_t this_size;
1062 get_num_sparse_tagged_entities( *tag_iter, this_size );
1063 dbgOut.printf( 2, "%18s %8lu %8lu %8lu %8lu 0x%7lx\n", name.c_str(), (unsigned long)this_size,
1064 (unsigned long)tag_iter->sparse_offset, (unsigned long)tag_iter->var_data_offset,
1065 (unsigned long)tag_iter->max_num_ents, (unsigned long)tag_iter->tag_id );
1066 }
1067 }
1068
1069 return MB_SUCCESS;
1070 }
1071
1072 struct DatasetVals
1073 {
1074 long start_id;
1075 long max_count;
1076 long total;
1077 };
1078 STATIC_ASSERT( ( sizeof( DatasetVals ) == 3 * sizeof( long ) ) );
1079
1080 ErrorCode WriteHDF5Parallel::create_dataset( int num_datasets,
1081 const long* num_owned,
1082 long* offsets_out,
1083 long* max_proc_entities,
1084 long* total_entities,
1085 const DataSetCreator& creator,
1086 ExportSet* groups[],
1087 wid_t* first_ids_out )
1088 {
1089 int result;
1090 ErrorCode rval;
1091 const unsigned rank = myPcomm->proc_config().proc_rank();
1092 const unsigned nproc = myPcomm->proc_config().proc_size();
1093 const MPI_Comm comm = myPcomm->proc_config().proc_comm();
1094
1095
1096 std::vector< long > counts( rank ? 0 : nproc * num_datasets );
1097 (void)VALGRIND_CHECK_MEM_IS_DEFINED( &num_owned, sizeof( long ) );
1098 result = MPI_Gather( const_cast< long* >( num_owned ), num_datasets, MPI_LONG, &counts[0], num_datasets, MPI_LONG,
1099 0, comm );
1100 CHECK_MPI( result );
1101
1102
1103 DatasetVals zero_val = { 0, 0, 0 };
1104 std::vector< DatasetVals > cumulative( num_datasets, zero_val );
1105 if( rank == 0 )
1106 {
1107 for( unsigned i = 0; i < nproc; i++ )
1108 {
1109 const long* proc_data = &counts[i * num_datasets];
1110 for( int index = 0; index < num_datasets; ++index )
1111 {
1112 cumulative[index].total += proc_data[index];
1113 if( proc_data[index] > cumulative[index].max_count ) cumulative[index].max_count = proc_data[index];
1114 }
1115 }
1116
1117 for( int index = 0; index < num_datasets; ++index )
1118 {
1119 if( cumulative[index].total )
1120 {
1121 rval = creator( this, cumulative[index].total, groups ? groups[index] : 0, cumulative[index].start_id );
1122 CHECK_MB( rval );
1123 }
1124 else
1125 {
1126 cumulative[index].start_id = -1;
1127 }
1128 }
1129 }
1130
1131
1132 result = MPI_Bcast( (void*)&cumulative[0], 3 * num_datasets, MPI_LONG, 0, comm );
1133 CHECK_MPI( result );
1134 for( int index = 0; index < num_datasets; ++index )
1135 {
1136 if( first_ids_out ) first_ids_out[index] = (wid_t)cumulative[index].start_id;
1137 max_proc_entities[index] = cumulative[index].max_count;
1138 total_entities[index] = cumulative[index].total;
1139 }
1140
1141
1142 if( rank == 0 )
1143 {
1144
1145 std::vector< long > prev_size( counts.begin(), counts.begin() + num_datasets );
1146
1147 std::fill( counts.begin(), counts.begin() + num_datasets, 0L );
1148
1149 for( unsigned i = 1; i < nproc; ++i )
1150 {
1151
1152 long* prev_data = &counts[( i - 1 ) * num_datasets];
1153
1154 long* proc_data = &counts[i * num_datasets];
1155
1156 for( int j = 0; j < num_datasets; ++j )
1157 {
1158
1159 long mysize = proc_data[j];
1160
1161
1162 proc_data[j] = prev_data[j] + prev_size[j];
1163
1164 prev_size[j] = mysize;
1165 }
1166 }
1167 }
1168
1169
1170 if( rank == 0 )
1171 {
1172 (void)VALGRIND_CHECK_MEM_IS_DEFINED( &counts[0], num_datasets * nproc * sizeof( long ) );
1173 }
1174 result = MPI_Scatter( &counts[0], num_datasets, MPI_LONG, offsets_out, num_datasets, MPI_LONG, 0, comm );
1175 CHECK_MPI( result );
1176
1177 return MB_SUCCESS;
1178 }
1179
1180 ErrorCode WriteHDF5Parallel::create_node_table( int dimension )
1181 {
1182 nodeSet.num_nodes = dimension;
1183 struct NodeSetCreator : public DataSetCreator
1184 {
1185 ErrorCode operator()( WriteHDF5* file, long count, const ExportSet* group, long& start_id ) const
1186 {
1187 mhdf_Status status;
1188 hid_t handle = mhdf_createNodeCoords( file->file_ptr(), group->num_nodes, count, &start_id, &status );
1189 CHECK_HDFN( status );
1190 mhdf_closeData( file->file_ptr(), handle, &status );
1191 CHECK_HDFN( status );
1192 return MB_SUCCESS;
1193 }
1194 };
1195
1196 const long count = nodeSet.range.size();
1197 ExportSet* array[] = { &nodeSet };
1198 ErrorCode rval = create_dataset( 1, &count, &nodeSet.offset, &nodeSet.max_num_ents, &nodeSet.total_num_ents,
1199 NodeSetCreator(), array, &nodeSet.first_id );
1200 CHECK_MB( rval );
1201 return assign_ids( nodeSet.range, nodeSet.first_id + nodeSet.offset );
1202 }
1203
1204 struct elemtype
1205 {
1206 int mbtype;
1207 int numnode;
1208
1209 elemtype( int vals[2] ) : mbtype( vals[0] ), numnode( vals[1] ) {}
1210 elemtype( int t, int n ) : mbtype( t ), numnode( n ) {}
1211
1212 bool operator==( const elemtype& other ) const
1213 {
1214 return mbtype == other.mbtype && ( mbtype == MBENTITYSET || numnode == other.numnode );
1215 }
1216 bool operator<( const elemtype& other ) const
1217 {
1218 if( mbtype > other.mbtype ) return false;
1219
1220 return mbtype < other.mbtype || ( mbtype != MBENTITYSET && numnode < other.numnode );
1221 }
1222 bool operator!=( const elemtype& other ) const
1223 {
1224 return !this->operator==( other );
1225 }
1226 };
1227
1228 ErrorCode WriteHDF5Parallel::negotiate_type_list()
1229 {
1230 int result;
1231 const MPI_Comm comm = myPcomm->proc_config().proc_comm();
1232
1233 exportList.sort();
1234 int num_types = exportList.size();
1235
1236
1237 typedef std::vector< std::pair< int, int > > typelist;
1238 typelist my_types( num_types );
1239 (void)VALGRIND_MAKE_VEC_UNDEFINED( my_types );
1240 typelist::iterator viter = my_types.begin();
1241 for( std::list< ExportSet >::iterator eiter = exportList.begin(); eiter != exportList.end(); ++eiter )
1242 {
1243 viter->first = eiter->type;
1244 viter->second = eiter->num_nodes;
1245 ++viter;
1246 }
1247
1248 dbgOut.print( 2, "Local Element Types:\n" );
1249 for( viter = my_types.begin(); viter != my_types.end(); ++viter )
1250 {
1251 int type = viter->first;
1252 int count = viter->second;
1253 dbgOut.printf( 2, " %s : %d\n", CN::EntityTypeName( (EntityType)type ), count );
1254 }
1255
1256
1257 int num_types0 = num_types;
1258 result = MPI_Bcast( &num_types0, 1, MPI_INT, 0, comm );
1259 CHECK_MPI( result );
1260
1261 typelist root_types( num_types0 );
1262 if( 0 == myPcomm->proc_config().proc_rank() ) root_types = my_types;
1263 result = MPI_Bcast( (void*)&root_types[0], 2 * num_types0, MPI_INT, 0, comm );
1264 CHECK_MPI( result );
1265
1266
1267 typelist non_root_types;
1268 viter = root_types.begin();
1269 for( typelist::iterator iter = my_types.begin(); iter != my_types.end(); ++iter )
1270 {
1271 if( viter == root_types.end() || *viter != *iter )
1272 non_root_types.push_back( *iter );
1273 else
1274 ++viter;
1275 }
1276
1277
1278 int non_root_count = non_root_types.size();
1279 int not_done;
1280 result = MPI_Allreduce( &non_root_count, ¬_done, 1, MPI_INT, MPI_LOR, comm );
1281 CHECK_MPI( result );
1282 if( not_done )
1283 {
1284
1285 std::vector< int > counts( myPcomm->proc_config().proc_size() );
1286 int two_count = 2 * non_root_count;
1287 result = MPI_Gather( &two_count, 1, MPI_INT, &counts[0], 1, MPI_INT, 0, comm );
1288 CHECK_MPI( result );
1289
1290
1291 std::vector< int > displs( myPcomm->proc_config().proc_size() + 1 );
1292 (void)VALGRIND_MAKE_VEC_UNDEFINED( displs );
1293 displs[0] = 0;
1294 for( unsigned long i = 1; i <= myPcomm->proc_config().proc_size(); ++i )
1295 displs[i] = displs[i - 1] + counts[i - 1];
1296 int total = displs[myPcomm->proc_config().proc_size()];
1297 typelist alltypes( total / 2 );
1298 (void)VALGRIND_MAKE_VEC_UNDEFINED( alltypes );
1299 (void)VALGRIND_CHECK_MEM_IS_DEFINED( &non_root_types[0], non_root_types.size() * sizeof( int ) );
1300 result = MPI_Gatherv( (void*)&non_root_types[0], 2 * non_root_count, MPI_INT, (int*)&alltypes[0], &counts[0],
1301 &displs[0], MPI_INT, 0, comm );
1302 CHECK_MPI( result );
1303
1304
1305
1306
1307
1308 if( 0 == myPcomm->proc_config().proc_rank() )
1309 {
1310 for( viter = alltypes.begin(); viter != alltypes.end(); ++viter )
1311 {
1312 typelist::iterator titer = std::lower_bound( my_types.begin(), my_types.end(), *viter );
1313 if( titer == my_types.end() || *titer != *viter ) my_types.insert( titer, *viter );
1314 }
1315
1316 dbgOut.print( 2, "Global Element Types:\n" );
1317 for( viter = my_types.begin(); viter != my_types.end(); ++viter )
1318 dbgOut.printf( 2, " %s : %d\n", CN::EntityTypeName( (EntityType)viter->first ), viter->second );
1319 }
1320
1321
1322 total = my_types.size();
1323 result = MPI_Bcast( &total, 1, MPI_INT, 0, comm );
1324 CHECK_MPI( result );
1325
1326
1327 my_types.resize( total );
1328 result = MPI_Bcast( (void*)&my_types[0], 2 * total, MPI_INT, 0, comm );
1329 CHECK_MPI( result );
1330 }
1331 else
1332 {
1333
1334
1335
1336
1337 my_types.swap( root_types );
1338 }
1339
1340
1341
1342 std::list< ExportSet >::iterator ex_iter = exportList.begin();
1343 for( viter = my_types.begin(); viter != my_types.end(); ++viter )
1344 {
1345 while( ex_iter != exportList.end() && *ex_iter < *viter )
1346 ++ex_iter;
1347
1348 if( ex_iter == exportList.end() || !( *ex_iter == *viter ) )
1349 {
1350 ExportSet insert;
1351 insert.type = (EntityType)viter->first;
1352 insert.num_nodes = viter->second;
1353 insert.first_id = 0;
1354 insert.offset = 0;
1355 insert.adj_offset = 0;
1356 ex_iter = exportList.insert( ex_iter, insert );
1357 }
1358 }
1359
1360 return MB_SUCCESS;
1361 }
1362
1363 ErrorCode WriteHDF5Parallel::create_element_tables()
1364 {
1365 struct ElemSetCreator : public DataSetCreator
1366 {
1367 ErrorCode operator()( WriteHDF5* file, long size, const ExportSet* ex, long& start_id ) const
1368 {
1369 return file->create_elem_table( *ex, size, start_id );
1370 }
1371 };
1372
1373 const int numtypes = exportList.size();
1374 if (numtypes > 0)
1375 {
1376 std::vector< ExportSet* > groups( numtypes );
1377 std::vector< long > counts( numtypes ), offsets( numtypes ), max_ents( numtypes ), total_ents( numtypes );
1378 std::vector< wid_t > start_ids( numtypes );
1379
1380 size_t idx = 0;
1381 std::list< ExportSet >::iterator ex_iter;
1382 for( ex_iter = exportList.begin(); ex_iter != exportList.end(); ++ex_iter, ++idx )
1383 {
1384 groups[idx] = &*ex_iter;
1385 counts[idx] = ex_iter->range.size();
1386 }
1387 ErrorCode rval = create_dataset( numtypes, &counts[0], &offsets[0], &max_ents[0], &total_ents[0], ElemSetCreator(),
1388 &groups[0], &start_ids[0] );
1389 CHECK_MB( rval );
1390
1391 for( idx = 0, ex_iter = exportList.begin(); ex_iter != exportList.end(); ++ex_iter, ++idx )
1392 {
1393 ex_iter->first_id = start_ids[idx];
1394 ex_iter->offset = offsets[idx];
1395 ex_iter->max_num_ents = max_ents[idx];
1396 ex_iter->total_num_ents = total_ents[idx];
1397 rval = assign_ids( ex_iter->range, ex_iter->first_id + ex_iter->offset );
1398 CHECK_MB( rval );
1399 }
1400 }
1401
1402 return MB_SUCCESS;
1403 }
1404
1405 ErrorCode WriteHDF5Parallel::create_adjacency_tables()
1406 {
1407 struct AdjSetCreator : public DataSetCreator
1408 {
1409 ErrorCode operator()( WriteHDF5* file, long size, const ExportSet* ex, long& start_id ) const
1410 {
1411 mhdf_Status status;
1412 hid_t handle = mhdf_createAdjacency( file->file_ptr(), ex->name(), size, &status );
1413 CHECK_HDFN( status );
1414 mhdf_closeData( file->file_ptr(), handle, &status );
1415 CHECK_HDFN( status );
1416 start_id = -1;
1417 return MB_SUCCESS;
1418 }
1419 };
1420
1421 std::vector< ExportSet* > groups;
1422 #ifdef WRITE_NODE_ADJACENCIES
1423 groups.push_back( &nodeSet );
1424 #endif
1425 for( std::list< ExportSet >::iterator ex_iter = exportList.begin(); ex_iter != exportList.end(); ++ex_iter )
1426 groups.push_back( &*ex_iter );
1427
1428 ErrorCode rval;
1429 const int numtypes = groups.size();
1430 if (numtypes > 0)
1431 {
1432 std::vector< long > counts( numtypes );
1433 std::vector< long > offsets( numtypes );
1434 std::vector< long > max_ents( numtypes );
1435 std::vector< long > totals( numtypes );
1436 for( int i = 0; i < numtypes; ++i )
1437 {
1438 wid_t count;
1439 rval = count_adjacencies( groups[i]->range, count );
1440 CHECK_MB( rval );
1441 counts[i] = count;
1442 }
1443
1444 rval = create_dataset( numtypes, &counts[0], &offsets[0], &max_ents[0], &totals[0], AdjSetCreator(), &groups[0] );
1445 CHECK_MB( rval );
1446
1447
1448 for( int i = 0; i < numtypes; ++i )
1449 {
1450 groups[i]->max_num_adjs = max_ents[i];
1451 groups[i]->adj_offset = offsets[i];
1452 }
1453 }
1454 return MB_SUCCESS;
1455 }
1456
1457 const unsigned SSVB = 3;
1458
1459 void WriteHDF5Parallel::print_set_sharing_data( const Range& range, const char* label, Tag idt )
1460 {
1461 dbgOut.printf( SSVB, "set\tid\towner\t%-*s\tfid\tshared\n", (int)( sizeof( EntityHandle ) * 2 ), "handle" );
1462 for( Range::iterator it = range.begin(); it != range.end(); ++it )
1463 {
1464 int id;
1465 iFace->tag_get_data( idt, &*it, 1, &id );
1466 EntityHandle handle = 0;
1467 unsigned owner = 0;
1468 wid_t file_id = 0;
1469 myPcomm->get_entityset_owner( *it, owner, &handle );
1470 if( !idMap.find( *it, file_id ) ) file_id = 0;
1471 dbgOut.printf( SSVB, "%s\t%d\t%u\t%lx\t%lu\t", label, id, owner, (unsigned long)handle,
1472 (unsigned long)file_id );
1473 std::vector< unsigned > procs;
1474 myPcomm->get_entityset_procs( *it, procs );
1475 if( procs.empty() )
1476 dbgOut.print( SSVB, "<none>\n" );
1477 else
1478 {
1479 for( unsigned i = 0; i < procs.size() - 1; ++i )
1480 dbgOut.printf( SSVB, "%u,", procs[i] );
1481 dbgOut.printf( SSVB, "%u\n", procs.back() );
1482 }
1483 }
1484 }
1485
1486 void WriteHDF5Parallel::print_shared_sets()
1487 {
1488 const char* tag_names[][2] = { { MATERIAL_SET_TAG_NAME, "block" },
1489 { DIRICHLET_SET_TAG_NAME, "nodeset" },
1490 { NEUMANN_SET_TAG_NAME, "sideset" },
1491 { 0, 0 } };
1492
1493 for( int i = 0; tag_names[i][0]; ++i )
1494 {
1495 Tag tag;
1496 if( MB_SUCCESS != iFace->tag_get_handle( tag_names[i][0], 1, MB_TYPE_INTEGER, tag ) ) continue;
1497
1498 Range tagged;
1499 iFace->get_entities_by_type_and_tag( 0, MBENTITYSET, &tag, 0, 1, tagged );
1500 print_set_sharing_data( tagged, tag_names[i][1], tag );
1501 }
1502
1503 Tag geom, id;
1504 if( MB_SUCCESS != iFace->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geom ) ) return;
1505 id = iFace->globalId_tag();
1506
1507 const char* geom_names[] = { "vertex", "curve", "surface", "volume" };
1508 for( int d = 0; d <= 3; ++d )
1509 {
1510 Range tagged;
1511 const void* vals[] = { &d };
1512 iFace->get_entities_by_type_and_tag( 0, MBENTITYSET, &geom, vals, 1, tagged );
1513 print_set_sharing_data( tagged, geom_names[d], id );
1514 }
1515 }
1516
1517 ErrorCode WriteHDF5Parallel::communicate_shared_set_ids( const Range& owned, const Range& remote )
1518 {
1519 ErrorCode rval;
1520 int mperr;
1521 const int TAG = 0xD0E;
1522
1523 const MPI_Comm comm = myPcomm->proc_config().proc_comm();
1524
1525 dbgOut.tprint( 1, "COMMUNICATING SHARED SET IDS\n" );
1526 dbgOut.print( 6, "Owned, shared sets: ", owned );
1527
1528
1529
1530 std::vector< unsigned > procs;
1531 rval = myPcomm->get_entityset_owners( procs );
1532 CHECK_MB( rval );
1533 std::vector< unsigned >::iterator it = std::find( procs.begin(), procs.end(), myPcomm->proc_config().proc_rank() );
1534 if( it != procs.end() ) procs.erase( it );
1535
1536 std::vector< MPI_Request > recv_req( procs.size(), MPI_REQUEST_NULL );
1537 std::vector< std::vector< unsigned long > > recv_buf( procs.size() );
1538
1539 size_t recv_count = 0;
1540 for( size_t i = 0; i < procs.size(); ++i )
1541 {
1542 Range tmp;
1543 rval = myPcomm->get_owned_sets( procs[i], tmp );
1544 CHECK_MB( rval );
1545 size_t count =
1546 intersect( tmp, remote ).size();
1547 if( count )
1548 {
1549 dbgOut.printf( 6, "Sets owned by proc %u (remote handles): ", procs[i] );
1550 if( dbgOut.get_verbosity() >= 6 )
1551 {
1552 Range remote_handles;
1553 tmp = intersect( tmp, remote );
1554 for( Range::iterator j = tmp.begin(); j != tmp.end(); ++j )
1555 {
1556 unsigned r;
1557 EntityHandle h;
1558 myPcomm->get_entityset_owner( *j, r, &h );
1559 assert( r == procs[i] );
1560 remote_handles.insert( h );
1561 }
1562 dbgOut.print( 6, remote_handles );
1563 }
1564 recv_count++;
1565 recv_buf[i].resize( 2 * count + 1 );
1566 dbgOut.printf( 5, "Posting receive buffer of size %lu for proc %u (%lu of %lu owned sets)\n",
1567 (unsigned long)recv_buf[i].size(), procs[i], count, tmp.size() );
1568 mperr =
1569 MPI_Irecv( &recv_buf[i][0], recv_buf[i].size(), MPI_UNSIGNED_LONG, procs[i], TAG, comm, &recv_req[i] );
1570 CHECK_MPI( mperr );
1571 }
1572 }
1573
1574
1575
1576
1577 std::map< unsigned, Range > send_sets;
1578 std::vector< unsigned > set_procs;
1579 for( Range::reverse_iterator i = owned.rbegin(); i != owned.rend(); ++i )
1580 {
1581 set_procs.clear();
1582 rval = myPcomm->get_entityset_procs( *i, set_procs );
1583 CHECK_MB( rval );
1584 for( size_t j = 0; j < set_procs.size(); ++j )
1585 if( set_procs[j] != myPcomm->proc_config().proc_rank() ) send_sets[set_procs[j]].insert( *i );
1586 }
1587 assert( send_sets.find( myPcomm->proc_config().proc_rank() ) == send_sets.end() );
1588
1589
1590 std::vector< std::vector< unsigned long > > send_buf( send_sets.size() );
1591 std::vector< MPI_Request > send_req( send_sets.size() );
1592 std::map< unsigned, Range >::iterator si = send_sets.begin();
1593 for( size_t i = 0; si != send_sets.end(); ++si, ++i )
1594 {
1595 dbgOut.printf( 6, "Sending data for shared sets to proc %u: ", si->first );
1596 dbgOut.print( 6, si->second );
1597
1598 send_buf[i].reserve( 2 * si->second.size() + 1 );
1599 send_buf[i].push_back( si->second.size() );
1600 for( Range::iterator j = si->second.begin(); j != si->second.end(); ++j )
1601 {
1602 send_buf[i].push_back( *j );
1603 send_buf[i].push_back( idMap.find( *j ) );
1604 }
1605 dbgOut.printf( 5, "Sending buffer of size %lu to proc %u (%lu of %lu owned sets)\n",
1606 (unsigned long)send_buf[i].size(), si->first, si->second.size(), owned.size() );
1607 mperr = MPI_Isend( &send_buf[i][0], send_buf[i].size(), MPI_UNSIGNED_LONG, si->first, TAG, comm, &send_req[i] );
1608 }
1609
1610
1611 MPI_Status status;
1612 int idx;
1613 while( recv_count-- )
1614 {
1615 mperr = MPI_Waitany( recv_req.size(), &recv_req[0], &idx, &status );
1616 CHECK_MPI( mperr );
1617
1618 assert( (unsigned)status.MPI_SOURCE == procs[idx] );
1619 assert( 2 * recv_buf[idx].front() + 1 == recv_buf[idx].size() );
1620 const size_t n = std::min< size_t >( recv_buf[idx].front(), ( recv_buf[idx].size() - 1 ) / 2 );
1621 dbgOut.printf( 5, "Received buffer of size %lu from proc %d\n", (unsigned long)( 2 * n + 1 ),
1622 (int)status.MPI_SOURCE );
1623
1624 for( size_t i = 0; i < n; ++i )
1625 {
1626 EntityHandle handle = 0;
1627 rval = myPcomm->get_entityset_local_handle( procs[idx], recv_buf[idx][2 * i + 1], handle );
1628 CHECK_MB( rval );
1629 assert( handle != 0 );
1630 if( !idMap.insert( handle, recv_buf[idx][2 * i + 2], 1 ).second )
1631 error( MB_FAILURE );
1632 }
1633
1634 recv_req[idx] = MPI_REQUEST_NULL;
1635 }
1636 assert( MPI_SUCCESS == MPI_Waitany( recv_req.size(), &recv_req[0], &idx, &status ) &&
1637 MPI_UNDEFINED == idx );
1638
1639
1640
1641
1642 std::vector< MPI_Status > stats( send_req.size() );
1643 mperr = MPI_Waitall( send_req.size(), &send_req[0], &stats[0] );
1644 CHECK_MPI( mperr );
1645
1646 if( dbgOut.get_verbosity() >= SSVB ) print_shared_sets();
1647
1648 return MB_SUCCESS;
1649 }
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675 ErrorCode WriteHDF5Parallel::pack_set( Range::const_iterator it, unsigned long* buffer, size_t buffer_size )
1676 {
1677 ErrorCode rval;
1678 const EntityHandle* ptr;
1679 int len;
1680 unsigned char flags;
1681 std::vector< wid_t > tmp;
1682 size_t newlen;
1683
1684
1685 assert( buffer_size >= 4 );
1686 buffer_size -= 4;
1687
1688 Range::const_iterator nd = it;
1689 ++nd;
1690 rval = writeUtil->get_entity_list_pointers( it, nd, &ptr, WriteUtilIface::CONTENTS, &len, &flags );
1691 CHECK_MB( rval );
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704 if( len && !( flags & MESHSET_ORDERED ) )
1705 {
1706 tmp.clear();
1707 bool blocked = false;
1708 assert( ( 0 == len % 2 ) );
1709 rval = range_to_blocked_list( ptr, len / 2, tmp, blocked );
1710 CHECK_MB( rval );
1711 if( blocked ) flags |= mhdf_SET_RANGE_BIT;
1712 }
1713 else
1714 {
1715 tmp.resize( len );
1716 rval = vector_to_id_list( ptr, len, &tmp[0], newlen, true );
1717 CHECK_MB( rval );
1718 tmp.resize( newlen );
1719 }
1720
1721 buffer[0] = flags;
1722 buffer[1] = tmp.size();
1723 if( tmp.size() <= buffer_size ) std::copy( tmp.begin(), tmp.end(), buffer + 4 );
1724
1725 rval = writeUtil->get_entity_list_pointers( it, nd, &ptr, WriteUtilIface::CHILDREN, &len );
1726 CHECK_MB( rval );
1727 tmp.resize( len );
1728 rval = vector_to_id_list( ptr, len, &tmp[0], newlen, true );
1729 tmp.resize( newlen );
1730 buffer[2] = tmp.size();
1731 if( tmp.size() <= buffer_size - buffer[1] ) std::copy( tmp.begin(), tmp.end(), buffer + 4 + buffer[1] );
1732
1733 rval = writeUtil->get_entity_list_pointers( it, nd, &ptr, WriteUtilIface::PARENTS, &len );
1734 CHECK_MB( rval );
1735 tmp.resize( len );
1736 rval = vector_to_id_list( ptr, len, &tmp[0], newlen, true );
1737 tmp.resize( newlen );
1738 buffer[3] = tmp.size();
1739 if( tmp.size() <= buffer_size - buffer[1] - buffer[2] )
1740 std::copy( tmp.begin(), tmp.end(), buffer + 4 + buffer[1] + buffer[2] );
1741
1742 return MB_SUCCESS;
1743 }
1744
1745 template < typename TYPE >
1746 static void convert_to_ranged_ids( const TYPE* buffer, size_t len, std::vector< WriteHDF5::wid_t >& result )
1747 {
1748 if( !len )
1749 {
1750 result.clear();
1751 return;
1752 }
1753
1754 result.resize( len * 2 );
1755 Range tmp;
1756 for( size_t i = 0; i < len; i++ )
1757 tmp.insert( (EntityHandle)buffer[i] );
1758 result.resize( tmp.psize() * 2 );
1759 int j = 0;
1760 for( Range::const_pair_iterator pit = tmp.const_pair_begin(); pit != tmp.const_pair_end(); ++pit, j++ )
1761 {
1762 result[2 * j] = pit->first;
1763 result[2 * j + 1] = pit->second - pit->first + 1;
1764 }
1765 }
1766
1767 static void merge_ranged_ids( const unsigned long* range_list, size_t len, std::vector< WriteHDF5::wid_t >& result )
1768 {
1769 typedef WriteHDF5::wid_t wid_t;
1770 assert( 0 == len % 2 );
1771 assert( 0 == result.size() % 2 );
1772 STATIC_ASSERT( sizeof( std::pair< wid_t, wid_t > ) == 2 * sizeof( wid_t ) );
1773
1774 result.insert( result.end(), range_list, range_list + len );
1775 size_t plen = result.size() / 2;
1776 Range tmp;
1777 for( size_t i = 0; i < plen; i++ )
1778 {
1779 EntityHandle starth = (EntityHandle)result[2 * i];
1780 EntityHandle endh = (EntityHandle)result[2 * i] + (wid_t)result[2 * i + 1] - 1;
1781 tmp.insert( starth, endh );
1782 }
1783
1784 result.resize( tmp.psize() * 2 );
1785 int j = 0;
1786 for( Range::const_pair_iterator pit = tmp.const_pair_begin(); pit != tmp.const_pair_end(); ++pit, j++ )
1787 {
1788 result[2 * j] = pit->first;
1789 result[2 * j + 1] = pit->second - pit->first + 1;
1790 }
1791 }
1792
1793 static void merge_vector_ids( const unsigned long* list, size_t len, std::vector< WriteHDF5::wid_t >& result )
1794 {
1795 result.insert( result.end(), list, list + len );
1796 }
1797
1798 ErrorCode WriteHDF5Parallel::unpack_set( EntityHandle set, const unsigned long* buffer, size_t buffer_size )
1799 {
1800
1801 assert( buffer_size >= 4 );
1802 assert( buffer[1] + buffer[2] + buffer[3] <= buffer_size );
1803 const unsigned long flags = buffer[0];
1804 unsigned long num_content = buffer[1];
1805 const unsigned long num_child = buffer[2];
1806 const unsigned long num_parent = buffer[3];
1807 const unsigned long* contents = buffer + 4;
1808 const unsigned long* children = contents + num_content;
1809 const unsigned long* parents = children + num_child;
1810
1811 SpecialSetData* data = find_set_data( set );
1812 assert( NULL != data );
1813 if( NULL == data ) return MB_FAILURE;
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824 std::vector< wid_t > tmp;
1825 if( ( flags & mhdf_SET_RANGE_BIT ) != ( data->setFlags & mhdf_SET_RANGE_BIT ) )
1826 {
1827 if( flags & mhdf_SET_RANGE_BIT )
1828 {
1829 tmp = data->contentIds;
1830 convert_to_ranged_ids( &tmp[0], tmp.size(), data->contentIds );
1831 data->setFlags |= mhdf_SET_RANGE_BIT;
1832 }
1833 else
1834 {
1835 tmp.clear();
1836 convert_to_ranged_ids( contents, num_content, tmp );
1837 num_content = tmp.size();
1838 if( sizeof( wid_t ) < sizeof( long ) )
1839 {
1840 size_t old_size = tmp.size();
1841 tmp.resize( sizeof( long ) * old_size / sizeof( wid_t ) );
1842 unsigned long* array = reinterpret_cast< unsigned long* >( &tmp[0] );
1843 for( long i = ( (long)old_size ) - 1; i >= 0; --i )
1844 array[i] = tmp[i];
1845 contents = array;
1846 }
1847 else if( sizeof( wid_t ) > sizeof( long ) )
1848 {
1849 unsigned long* array = reinterpret_cast< unsigned long* >( &tmp[0] );
1850 std::copy( tmp.begin(), tmp.end(), array );
1851 }
1852 contents = reinterpret_cast< unsigned long* >( &tmp[0] );
1853 }
1854 }
1855
1856 if( data->setFlags & mhdf_SET_RANGE_BIT )
1857 merge_ranged_ids( contents, num_content, data->contentIds );
1858 else
1859 merge_vector_ids( contents, num_content, data->contentIds );
1860
1861 merge_vector_ids( children, num_child, data->childIds );
1862 merge_vector_ids( parents, num_parent, data->parentIds );
1863 return MB_SUCCESS;
1864 }
1865
1866 ErrorCode WriteHDF5Parallel::communicate_shared_set_data( const Range& owned, const Range& remote )
1867 {
1868 ErrorCode rval;
1869 int mperr;
1870 const unsigned rank = myPcomm->proc_config().proc_rank();
1871 const MPI_Comm comm = myPcomm->proc_config().proc_comm();
1872
1873 dbgOut.tprintf( 1, "COMMUNICATING SHARED SET DATA (%lu owned & %lu remote)\n", (unsigned long)owned.size(),
1874 (unsigned long)remote.size() );
1875
1876
1877 size_t nummess = 0;
1878 std::vector< unsigned > procs;
1879 ;
1880 Range shared( owned );
1881 shared.merge( remote );
1882 for( Range::iterator i = shared.begin(); i != shared.end(); ++i )
1883 {
1884 procs.clear();
1885 rval = myPcomm->get_entityset_procs( *i, procs );
1886 CHECK_MB( rval );
1887 nummess += procs.size();
1888 }
1889
1890
1891
1892
1893
1894
1895 const size_t MAX_BUFFER_MEM = 32 * 1024 * 1024 / sizeof( long );
1896
1897 const size_t INIT_BUFFER_SIZE = 1024;
1898 const size_t MIN_BUFFER_SIZE = 16;
1899 size_t init_buff_size = INIT_BUFFER_SIZE;
1900 if( init_buff_size * nummess > MAX_BUFFER_MEM ) init_buff_size = MAX_BUFFER_MEM / nummess;
1901 if( init_buff_size < MIN_BUFFER_SIZE ) init_buff_size = MIN_BUFFER_SIZE;
1902
1903 dbgOut.printf( 2, "Using buffer size of %lu for an expected message count of %lu\n", (unsigned long)init_buff_size,
1904 (unsigned long)nummess );
1905
1906
1907 size_t numrecv = 0;
1908 for( Range::iterator i = owned.begin(); i != owned.end(); ++i )
1909 {
1910 procs.clear();
1911 rval = myPcomm->get_entityset_procs( *i, procs );
1912 CHECK_MB( rval );
1913 numrecv += procs.size();
1914 if( std::find( procs.begin(), procs.end(), rank ) != procs.end() ) --numrecv;
1915 }
1916
1917
1918 std::vector< MPI_Request > recv_req( numrecv, MPI_REQUEST_NULL );
1919 std::vector< MPI_Request > lrecv_req( numrecv, MPI_REQUEST_NULL );
1920
1921 std::vector< std::vector< unsigned long > > recv_buf( numrecv, std::vector< unsigned long >( init_buff_size ) );
1922 int idx = 0;
1923 for( Range::iterator i = owned.begin(); i != owned.end(); ++i )
1924 {
1925 procs.clear();
1926 rval = myPcomm->get_entityset_procs( *i, procs );
1927 CHECK_MB( rval );
1928 for( size_t j = 0; j < procs.size(); ++j )
1929 {
1930 if( procs[j] == rank ) continue;
1931 int tag = ID_FROM_HANDLE( *i );
1932 if( *i != CREATE_HANDLE( MBENTITYSET, tag ) )
1933 {
1934 #ifndef NDEBUG
1935 abort();
1936 #endif
1937 CHECK_MB( MB_FAILURE );
1938 }
1939 dbgOut.printf( 5, "Posting buffer to receive set %d from proc %u\n", tag, procs[j] );
1940 mperr =
1941 MPI_Irecv( &recv_buf[idx][0], init_buff_size, MPI_UNSIGNED_LONG, procs[j], tag, comm, &recv_req[idx] );
1942 CHECK_MPI( mperr );
1943 ++idx;
1944 }
1945 }
1946 assert( (size_t)idx == numrecv );
1947
1948
1949 std::vector< MPI_Request > send_req( remote.size() );
1950 std::vector< std::vector< unsigned long > > send_buf( remote.size() );
1951 idx = 0;
1952 for( Range::iterator i = remote.begin(); i != remote.end(); ++i, ++idx )
1953 {
1954 send_buf[idx].resize( init_buff_size );
1955 rval = pack_set( i, &send_buf[idx][0], init_buff_size );
1956 CHECK_MB( rval );
1957 EntityHandle remote_handle;
1958 unsigned owner;
1959 rval = myPcomm->get_entityset_owner( *i, owner, &remote_handle );
1960 CHECK_MB( rval );
1961
1962 int tag = ID_FROM_HANDLE( remote_handle );
1963 assert( remote_handle == CREATE_HANDLE( MBENTITYSET, tag ) );
1964 dbgOut.printf( 5, "Sending %lu values for set %d to proc %u\n",
1965 send_buf[idx][1] + send_buf[idx][2] + send_buf[idx][3] + 4, tag, owner );
1966 mperr = MPI_Isend( &send_buf[idx][0], init_buff_size, MPI_UNSIGNED_LONG, owner, tag, comm, &send_req[idx] );
1967 CHECK_MPI( mperr );
1968 }
1969
1970
1971
1972
1973
1974 assert( specialSets.empty() );
1975 specialSets.clear();
1976 specialSets.reserve( owned.size() );
1977 for( Range::iterator i = owned.begin(); i != owned.end(); ++i )
1978 {
1979
1980
1981
1982
1983
1984 SpecialSetData data;
1985 data.setHandle = *i;
1986 rval = iFace->get_meshset_options( *i, data.setFlags );
1987 CHECK_MB( rval );
1988 specialSets.push_back( data );
1989 std::vector< EntityHandle > list;
1990 if( data.setFlags & MESHSET_ORDERED )
1991 {
1992 list.clear();
1993 rval = iFace->get_entities_by_handle( *i, list );
1994 CHECK_MB( rval );
1995 rval = vector_to_id_list( list, specialSets.back().contentIds, true );
1996 CHECK_MB( rval );
1997
1998
1999 }
2000 else
2001 {
2002 Range range;
2003 rval = iFace->get_entities_by_handle( *i, range );
2004 CHECK_MB( rval );
2005 bool ranged;
2006 rval = range_to_blocked_list( range, specialSets.back().contentIds, ranged );
2007 if( ranged ) specialSets.back().setFlags |= mhdf_SET_RANGE_BIT;
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017 }
2018
2019 list.clear();
2020 rval = iFace->get_parent_meshsets( *i, list );
2021 CHECK_MB( rval );
2022 rval = vector_to_id_list( list, specialSets.back().parentIds, true );
2023 CHECK_MB( rval );
2024 rval = iFace->get_child_meshsets( *i, list );
2025 CHECK_MB( rval );
2026 rval = vector_to_id_list( list, specialSets.back().childIds, true );
2027 CHECK_MB( rval );
2028 }
2029
2030
2031 size_t remaining = numrecv;
2032 numrecv = 0;
2033 while( remaining-- )
2034 {
2035 std::vector< unsigned long > dead;
2036 MPI_Status status;
2037 mperr = MPI_Waitany( recv_req.size(), &recv_req[0], &idx, &status );
2038 CHECK_MPI( mperr );
2039 EntityHandle handle = CREATE_HANDLE( MBENTITYSET, status.MPI_TAG );
2040 std::vector< unsigned long >& buff = recv_buf[idx];
2041 size_t size = buff[1] + buff[2] + buff[3] + 4;
2042 dbgOut.printf( 5, "Received %lu values for set %d from proc %d\n", (unsigned long)size, status.MPI_TAG,
2043 status.MPI_SOURCE );
2044 if( size <= init_buff_size )
2045 {
2046 rval = unpack_set( handle, &buff[0], init_buff_size );
2047 CHECK_MB( rval );
2048 dead.swap( buff );
2049 }
2050 else
2051 {
2052
2053
2054 buff.resize( size );
2055 dbgOut.printf( 5, "Re-Posting buffer to receive set %d from proc %d with size %lu\n", status.MPI_TAG,
2056 status.MPI_SOURCE, (unsigned long)size );
2057 mperr = MPI_Irecv( &buff[0], size, MPI_UNSIGNED_LONG, status.MPI_SOURCE, status.MPI_TAG, comm,
2058 &lrecv_req[idx] );
2059 CHECK_MPI( mperr );
2060 ++numrecv;
2061 }
2062 recv_req[idx] = MPI_REQUEST_NULL;
2063 }
2064
2065
2066 MPI_Waitall( send_req.size(), &send_req[0], MPI_STATUSES_IGNORE );
2067
2068
2069 idx = 0;
2070 for( Range::iterator i = remote.begin(); i != remote.end(); ++i, ++idx )
2071 {
2072 std::vector< unsigned long >& buff = send_buf[idx];
2073 size_t size = buff[1] + buff[2] + buff[3] + 4;
2074 if( size <= init_buff_size ) continue;
2075
2076 buff.resize( size );
2077 rval = pack_set( i, &buff[0], size );
2078 CHECK_MB( rval );
2079 EntityHandle remote_handle;
2080 unsigned owner;
2081 rval = myPcomm->get_entityset_owner( *i, owner, &remote_handle );
2082 CHECK_MB( rval );
2083
2084 int tag = ID_FROM_HANDLE( remote_handle );
2085 assert( remote_handle == CREATE_HANDLE( MBENTITYSET, tag ) );
2086 dbgOut.printf( 5, "Sending %lu values for set %d to proc %u\n", (unsigned long)size, tag, owner );
2087 mperr = MPI_Isend( &buff[0], size, MPI_UNSIGNED_LONG, owner, tag, comm, &send_req[idx] );
2088 CHECK_MPI( mperr );
2089 }
2090
2091
2092 remaining = numrecv;
2093 while( remaining-- )
2094 {
2095 std::vector< unsigned long > dead;
2096 MPI_Status status;
2097 mperr = MPI_Waitany( lrecv_req.size(), &lrecv_req[0], &idx, &status );
2098 CHECK_MPI( mperr );
2099 EntityHandle handle = CREATE_HANDLE( MBENTITYSET, status.MPI_TAG );
2100 std::vector< unsigned long >& buff = recv_buf[idx];
2101 dbgOut.printf( 5, "Received %lu values for set %d from proc %d\n", 4 + buff[1] + buff[2] + buff[3],
2102 status.MPI_TAG, status.MPI_SOURCE );
2103 rval = unpack_set( handle, &buff[0], buff.size() );
2104 CHECK_MB( rval );
2105 dead.swap( buff );
2106
2107 lrecv_req[idx] = MPI_REQUEST_NULL;
2108 }
2109
2110
2111 MPI_Waitall( send_req.size(), &send_req[0], MPI_STATUSES_IGNORE );
2112
2113 return MB_SUCCESS;
2114 }
2115
2116 ErrorCode WriteHDF5Parallel::create_meshset_tables( double* times )
2117 {
2118 Range::const_iterator riter;
2119 const unsigned rank = myPcomm->proc_config().proc_rank();
2120
2121 START_SERIAL;
2122 print_type_sets( iFace, &dbgOut, setSet.range );
2123 END_SERIAL;
2124 CpuTimer timer;
2125
2126
2127 Range shared, owned, remote;
2128 ErrorCode rval = myPcomm->get_shared_sets( shared );
2129 CHECK_MB( rval );
2130 shared = intersect( shared, setSet.range );
2131 rval = myPcomm->get_owned_sets( rank, owned );
2132 CHECK_MB( rval );
2133 owned = intersect( owned, setSet.range );
2134 remote = subtract( shared, owned );
2135 setSet.range = subtract( setSet.range, remote );
2136
2137
2138 struct SetDescCreator : public DataSetCreator
2139 {
2140 ErrorCode operator()( WriteHDF5* writer, long size, const ExportSet*, long& start_id ) const
2141 {
2142 return writer->create_set_meta( size, start_id );
2143 }
2144 };
2145 long count = setSet.range.size();
2146 rval = create_dataset( 1, &count, &setSet.offset, &setSet.max_num_ents, &setSet.total_num_ents, SetDescCreator(),
2147 NULL, &setSet.first_id );
2148 CHECK_MB( rval );
2149 writeSets = setSet.max_num_ents > 0;
2150
2151 rval = assign_ids( setSet.range, setSet.first_id + setSet.offset );
2152 CHECK_MB( rval );
2153 if( times ) times[SET_OFFSET_TIME] = timer.time_elapsed();
2154
2155
2156 rval = communicate_shared_set_ids( owned, remote );
2157 CHECK_MB( rval );
2158 if( times ) times[SHARED_SET_IDS] = timer.time_elapsed();
2159
2160
2161 rval = communicate_shared_set_data( owned, remote );
2162 CHECK_MB( rval );
2163 if( times ) times[SHARED_SET_CONTENTS] = timer.time_elapsed();
2164
2165
2166 long data_counts[3];
2167 rval = count_set_size( setSet.range, data_counts[0], data_counts[1], data_counts[2] );
2168 CHECK_MB( rval );
2169 if( times ) times[SET_OFFSET_TIME] += timer.time_elapsed();
2170
2171 long offsets[3], max_counts[3], totals[3];
2172 rval = create_dataset( 3, data_counts, offsets, max_counts, totals );
2173 CHECK_MB( rval );
2174
2175
2176 if( 0 == myPcomm->proc_config().proc_rank() )
2177 {
2178 rval = create_set_tables( totals[0], totals[1], totals[2] );
2179 CHECK_MB( rval );
2180 }
2181
2182
2183 setContentsOffset = offsets[0];
2184 setChildrenOffset = offsets[1];
2185 setParentsOffset = offsets[2];
2186 maxNumSetContents = max_counts[0];
2187 maxNumSetChildren = max_counts[1];
2188 maxNumSetParents = max_counts[2];
2189 writeSetContents = totals[0] > 0;
2190 writeSetChildren = totals[1] > 0;
2191 writeSetParents = totals[2] > 0;
2192
2193 dbgOut.printf( 2, "set contents: %ld local, %ld global, offset = %ld\n", data_counts[0], totals[0], offsets[0] );
2194 dbgOut.printf( 2, "set children: %ld local, %ld global, offset = %ld\n", data_counts[1], totals[1], offsets[1] );
2195 dbgOut.printf( 2, "set parents: %ld local, %ld global, offset = %ld\n", data_counts[2], totals[2], offsets[2] );
2196
2197 return MB_SUCCESS;
2198 }
2199
2200 void WriteHDF5Parallel::remove_remote_entities( EntityHandle relative, Range& range )
2201 {
2202 Range result;
2203 result.merge( intersect( range, nodeSet.range ) );
2204 result.merge( intersect( range, setSet.range ) );
2205 for( std::list< ExportSet >::iterator eiter = exportList.begin(); eiter != exportList.end(); ++eiter )
2206 result.merge( intersect( range, eiter->range ) );
2207
2208
2209 Range sets;
2210 int junk;
2211 sets.merge( Range::lower_bound( range.begin(), range.end(), CREATE_HANDLE( MBENTITYSET, 0, junk ) ), range.end() );
2212 remove_remote_sets( relative, sets );
2213 result.merge( sets );
2214 range.swap( result );
2215 }
2216
2217 void WriteHDF5Parallel::remove_remote_sets( EntityHandle , Range& range )
2218 {
2219 Range result( intersect( range, setSet.range ) );
2220
2221
2222 range.swap( result );
2223 }
2224
2225 void WriteHDF5Parallel::remove_remote_entities( EntityHandle relative, std::vector< EntityHandle >& vect )
2226 {
2227 Range intrsct;
2228 for( std::vector< EntityHandle >::const_iterator iter = vect.begin(); iter != vect.end(); ++iter )
2229 intrsct.insert( *iter );
2230 remove_remote_entities( relative, intrsct );
2231
2232 unsigned int read, write;
2233 for( read = write = 0; read < vect.size(); ++read )
2234 {
2235 if( intrsct.find( vect[read] ) != intrsct.end() )
2236 {
2237 if( read != write ) vect[write] = vect[read];
2238 ++write;
2239 }
2240 }
2241 if( write != vect.size() ) vect.resize( write );
2242 }
2243
2244 void WriteHDF5Parallel::remove_remote_sets( EntityHandle relative, std::vector< EntityHandle >& vect )
2245 {
2246 Range intrsct;
2247 for( std::vector< EntityHandle >::const_iterator iter = vect.begin(); iter != vect.end(); ++iter )
2248 intrsct.insert( *iter );
2249 remove_remote_sets( relative, intrsct );
2250
2251 unsigned int read, write;
2252 for( read = write = 0; read < vect.size(); ++read )
2253 {
2254 if( intrsct.find( vect[read] ) != intrsct.end() )
2255 {
2256 if( read != write ) vect[write] = vect[read];
2257 ++write;
2258 }
2259 }
2260 if( write != vect.size() ) vect.resize( write );
2261 }
2262
2263 ErrorCode WriteHDF5Parallel::exchange_file_ids( const Range& nonlocal )
2264 {
2265 ErrorCode rval;
2266
2267
2268
2269
2270
2271
2272
2273
2274 Range imesh, tmp;
2275 for( std::list< ExportSet >::reverse_iterator i = exportList.rbegin(); i != exportList.rend(); ++i )
2276 {
2277 tmp.clear();
2278 rval = myPcomm->filter_pstatus( i->range, PSTATUS_SHARED, PSTATUS_AND, -1, &tmp );
2279 if( MB_SUCCESS != rval ) return error( rval );
2280 imesh.merge( tmp );
2281 }
2282 tmp.clear();
2283 rval = myPcomm->filter_pstatus( nodeSet.range, PSTATUS_SHARED, PSTATUS_AND, -1, &tmp );
2284 if( MB_SUCCESS != rval ) return error( rval );
2285 imesh.merge( tmp );
2286
2287
2288 EntityHandle default_val = 0;
2289 Tag file_id_tag = 0;
2290 rval = iFace->tag_get_handle( "__hdf5_ll_fileid", 1, MB_TYPE_HANDLE, file_id_tag, MB_TAG_DENSE | MB_TAG_CREAT,
2291 &default_val );
2292 if( MB_SUCCESS != rval ) return error( rval );
2293
2294
2295 std::vector< EntityHandle > file_id_vect( imesh.size() );
2296 Range::const_iterator i;
2297 std::vector< EntityHandle >::iterator j = file_id_vect.begin();
2298 for( i = imesh.begin(); i != imesh.end(); ++i, ++j )
2299 {
2300 *j = idMap.find( *i );
2301 if( !*j )
2302 {
2303 iFace->tag_delete( file_id_tag );
2304 return error( MB_FAILURE );
2305 }
2306 }
2307 rval = iFace->tag_set_data( file_id_tag, imesh, &file_id_vect[0] );
2308 if( MB_SUCCESS != rval )
2309 {
2310 iFace->tag_delete( file_id_tag );
2311 return error( rval );
2312 }
2313
2314
2315 rval = myPcomm->exchange_tags( file_id_tag, imesh );
2316 if( MB_SUCCESS != rval )
2317 {
2318 iFace->tag_delete( file_id_tag );
2319 return error( rval );
2320 }
2321
2322
2323 file_id_vect.resize( nonlocal.size() );
2324 rval = iFace->tag_get_data( file_id_tag, nonlocal, &file_id_vect[0] );
2325 if( MB_SUCCESS != rval )
2326 {
2327 iFace->tag_delete( file_id_tag );
2328 return error( rval );
2329 }
2330
2331 j = file_id_vect.begin();
2332 for( i = nonlocal.begin(); i != nonlocal.end(); ++i, ++j )
2333 {
2334 if( *j == 0 )
2335 {
2336 int owner = -1;
2337 myPcomm->get_owner( *i, owner );
2338 const char* name = CN::EntityTypeName( TYPE_FROM_HANDLE( *i ) );
2339 int id = ID_FROM_HANDLE( *i );
2340 MB_SET_ERR_CONT( "Process " << myPcomm->proc_config().proc_rank()
2341 << " did not receive valid id handle for shared " << name << " " << id
2342 << " owned by process " << owner );
2343 dbgOut.printf( 1,
2344 "Did not receive valid remote id for "
2345 "shared %s %d owned by process %d",
2346 name, id, owner );
2347 iFace->tag_delete( file_id_tag );
2348 return error( MB_FAILURE );
2349 }
2350 else
2351 {
2352 if( !idMap.insert( *i, *j, 1 ).second )
2353 {
2354 iFace->tag_delete( file_id_tag );
2355 return error( MB_FAILURE );
2356 }
2357 }
2358 }
2359
2360 #ifndef NDEBUG
2361
2362
2363
2364 file_id_vect.resize( imesh.size() );
2365 rval = iFace->tag_get_data( file_id_tag, imesh, &file_id_vect[0] );
2366 if( MB_SUCCESS != rval )
2367 {
2368 iFace->tag_delete( file_id_tag );
2369 return error( rval );
2370 }
2371 int invalid_count = 0;
2372 j = file_id_vect.begin();
2373 for( i = imesh.begin(); i != imesh.end(); ++i, ++j )
2374 {
2375 EntityHandle h = idMap.find( *i );
2376 if( *j != h )
2377 {
2378 ++invalid_count;
2379 dbgOut.printf( 1, "Conflicting ownership for %s %ld\n", CN::EntityTypeName( TYPE_FROM_HANDLE( *i ) ),
2380 (long)ID_FROM_HANDLE( *i ) );
2381 }
2382 }
2383 if( invalid_count )
2384 {
2385 iFace->tag_delete( file_id_tag );
2386 MB_SET_ERR( MB_FAILURE, invalid_count << " entities with conflicting ownership found by process "
2387 << myPcomm->proc_config().proc_rank()
2388 << ". This will result in duplicate entities written to file" );
2389 }
2390 #endif
2391
2392 return iFace->tag_delete( file_id_tag );
2393 }
2394
2395 void WriteHDF5Parallel::print_times( const double* times ) const
2396 {
2397 if( !myPcomm )
2398 {
2399 WriteHDF5::print_times( times );
2400 }
2401 else
2402 {
2403 double recv[NUM_TIMES];
2404 MPI_Reduce( (void*)times, recv, NUM_TIMES, MPI_DOUBLE, MPI_MAX, 0, myPcomm->proc_config().proc_comm() );
2405 if( 0 == myPcomm->proc_config().proc_rank() ) WriteHDF5::print_times( recv );
2406 }
2407 }
2408
2409 }