Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 #include "iMeshP.h" 00002 #include "moab_mpi.h" 00003 #include <iostream> 00004 #include <algorithm> 00005 #include <vector> 00006 #include <sstream> 00007 #include <cassert> 00008 #include <cmath> 00009 #include <map> 00010 #include <cstring> 00011 #include <cstdio> // remove() 00012 00013 #if !defined( _MSC_VER ) && !defined( __MINGW32__ ) 00014 #include <unistd.h> 00015 #endif 00016 00017 #define STRINGIFY_( X ) #X 00018 #define STRINGIFY( X ) STRINGIFY_( X ) 00019 const char* const FILENAME = "iMeshP_test_file"; 00020 00021 /************************************************************************** 00022 Error Checking 00023 **************************************************************************/ 00024 00025 #define CHKERR \ 00026 do \ 00027 { \ 00028 if( ierr ) \ 00029 { \ 00030 std::cerr << "Error code " << ierr << " at " << __FILE__ << ":" << __LINE__ << std::endl; \ 00031 return ierr; \ 00032 } \ 00033 } while( false ) 00034 00035 #define PCHECK \ 00036 do \ 00037 { \ 00038 ierr = is_any_proc_error( ierr ); \ 00039 CHKERR; \ 00040 } while( false ) 00041 00042 // Use my_rank instead of rank to avoid shadowed declaration 00043 #define ASSERT( A ) \ 00044 do \ 00045 { \ 00046 if( is_any_proc_error( !( A ) ) ) \ 00047 { \ 00048 int my_rank = 0; \ 00049 MPI_Comm_rank( MPI_COMM_WORLD, &my_rank ); \ 00050 if( 0 == my_rank ) \ 00051 std::cerr << "Failed assertion: " #A << std::endl << " at " __FILE__ ":" << __LINE__ << std::endl; \ 00052 return 1; \ 00053 } \ 00054 } while( false ) 00055 00056 // Test if is_my_error is non-zero on any processor in MPI_COMM_WORLD 00057 int is_any_proc_error( int is_my_error ) 00058 { 00059 int result; 00060 int err = MPI_Allreduce( &is_my_error, &result, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD ); 00061 return err || result; 00062 } 00063 00064 /************************************************************************** 00065 Test Declarations 00066 **************************************************************************/ 00067 00068 class PartMap; 00069 00070 /**\brief Consistency check for parallel load 00071 * 00072 * All other tests depend on this one. 00073 */ 00074 int test_load( iMesh_Instance, iMeshP_PartitionHandle prtn, PartMap& map, int comm_size ); 00075 00076 /**\brief Test partition query methods 00077 * 00078 * Test: 00079 * - iMeshP_getPartitionComm 00080 * - iMeshP_getNumPartitions 00081 * - iMeshP_getPartitions 00082 */ 00083 int test_get_partitions( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00084 00085 /**\brief Test part quyery methods 00086 * 00087 * Test: 00088 * - iMeshP_getNumGlobalParts 00089 * - iMeshP_getNumLocalParts 00090 * - iMeshP_getLocalParts 00091 */ 00092 int test_get_parts( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00093 00094 /**\brief Test query by entity type 00095 * 00096 * Test: 00097 * - iMeshP_getNumOfTypeAll 00098 * - iMeshP_getNumOfType 00099 * - iMeshP_getEntities 00100 * - 00101 */ 00102 int test_get_by_type( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00103 00104 /**\brief Test query by entity topology 00105 * 00106 * Test: 00107 * - iMeshP_getNumOfTopoAll 00108 * - iMeshP_getNumOfTopo 00109 * - iMeshP_getEntities 00110 * - 00111 */ 00112 int test_get_by_topo( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00113 00114 /**\brief Test mapping from part id to part handle 00115 * 00116 * Test: 00117 * - iMeshP_getPartIdFromPartHandle 00118 * - iMeshP_getPartIdsFromPartHandlesArr 00119 * - iMeshP_getPartHandleFromPartId 00120 * - iMeshP_getPartHandlesFromPartsIdsArr 00121 * - iMeshP_getRankOfPart 00122 * - iMeshP_getRankOfPartArr 00123 */ 00124 int test_part_id_handle( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00125 00126 /**\brief Test get part rank 00127 * 00128 * Tests: 00129 * - iMeshP_getRankOfPart 00130 * - iMeshP_getRankOfPartArr 00131 */ 00132 int test_part_rank( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00133 00134 /**\brief Test querying of part neighbors 00135 * 00136 * Test: 00137 * - iMeshP_getNumPartNbors 00138 * - iMeshP_getNumPartNborsArr 00139 * - iMeshP_getPartNbors 00140 * - iMeshP_getPartNborsArr 00141 */ 00142 int test_get_neighbors( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00143 00144 /**\brief Test querying of part boundary entities 00145 * 00146 * Test: 00147 * - iMeshP_getNumPartBdryEnts 00148 * - iMeshP_getPartBdryEnts 00149 */ 00150 int test_get_part_boundary( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00151 00152 /**\brief Test querying of part boundary entities 00153 * 00154 * Test: 00155 * - iMeshP_initPartBdryEntIter 00156 * - iMeshP_initPartBdryEntArrIter 00157 */ 00158 int test_part_boundary_iter( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00159 00160 /**\brief Test adjacent entity query 00161 * 00162 * Test: 00163 * - iMeshP_getAdjEntities 00164 */ 00165 int test_get_adjacencies( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00166 00167 /**\brief Test entity iterators 00168 * 00169 * Test: 00170 * - iMeshP_initEntIter 00171 * - iMeshP_initEntArrIter 00172 */ 00173 int test_entity_iterator( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00174 00175 /**\brief Test entity owner queries 00176 * 00177 * Test: 00178 * - iMeshP_getEntOwnerPart 00179 * - iMeshP_getEntOwnerPartArr 00180 * - iMeshP_isEntOwner 00181 * - iMeshP_isEntOwnerArr 00182 */ 00183 int test_entity_owner( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00184 00185 /**\brief Test entity status 00186 * 00187 * Test: 00188 * - iMeshP_getEntStatus 00189 * - iMeshP_getEntStatusArr 00190 */ 00191 int test_entity_status( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00192 00193 /**\brief Test information about entity copies for interface entities 00194 * 00195 * Test: 00196 * - iMeshP_getNumCopies 00197 * - iMeshP_getCopyParts 00198 */ 00199 int test_entity_copy_parts( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00200 00201 /**\brief Test information about entity copies for interface entities 00202 * 00203 * Test: 00204 * - iMeshP_getCopies 00205 * - iMeshP_getCopyOnPart 00206 * - iMeshP_getOwnerCopy 00207 */ 00208 int test_entity_copies( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00209 00210 /**\brief Test creation of ghost entities 00211 * 00212 * Test: 00213 * - iMeshP_createGhostEntsAll 00214 */ 00215 int test_create_ghost_ents( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00216 00217 /**\brief Test commuinication of tag data 00218 * 00219 * Test: 00220 * - iMeshP_pushTags 00221 * - iMeshP_pushTagsEnt 00222 */ 00223 int test_push_tag_data_iface( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00224 int test_push_tag_data_ghost( iMesh_Instance, iMeshP_PartitionHandle prtn, const PartMap& ); 00225 00226 int test_exchange_ents( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ); 00227 00228 /************************************************************************** 00229 Helper Funcions 00230 **************************************************************************/ 00231 00232 class PartMap 00233 { 00234 public: 00235 int num_parts() const 00236 { 00237 return sortedPartList.size(); 00238 } 00239 00240 iMeshP_Part part_id_from_local_id( int local_id ) const 00241 { 00242 return sortedPartList[idx_from_local_id( local_id )]; 00243 } 00244 00245 int local_id_from_part_id( iMeshP_Part part ) const 00246 { 00247 return partLocalIds[idx_from_part_id( part )]; 00248 } 00249 00250 int rank_from_part_id( iMeshP_Part part ) const 00251 { 00252 return partRanks[idx_from_part_id( part )]; 00253 } 00254 00255 int rank_from_local_id( int id ) const 00256 { 00257 return partRanks[idx_from_local_id( id )]; 00258 } 00259 00260 int count_from_rank( int rank ) const 00261 { 00262 return std::count( partRanks.begin(), partRanks.end(), rank ); 00263 } 00264 00265 void part_id_from_rank( int rank, std::vector< iMeshP_Part >& parts ) const; 00266 00267 void local_id_from_rank( int rank, std::vector< int >& ids ) const; 00268 00269 const std::vector< iMeshP_Part >& get_parts() const 00270 { 00271 return sortedPartList; 00272 } 00273 00274 const std::vector< int >& get_ranks() const 00275 { 00276 return partRanks; 00277 } 00278 00279 int build_map( iMesh_Instance imesh, iMeshP_PartitionHandle partition, int num_expected_parts ); 00280 00281 static int part_from_coords( iMesh_Instance imesh, iMeshP_PartHandle part, int& id_out ); 00282 00283 private: 00284 inline int idx_from_part_id( iMeshP_Part id ) const 00285 { 00286 return std::lower_bound( sortedPartList.begin(), sortedPartList.end(), id ) - sortedPartList.begin(); 00287 } 00288 inline int idx_from_local_id( int id ) const 00289 { 00290 return localIdReverseMap[id]; 00291 } 00292 00293 std::vector< iMeshP_Part > sortedPartList; 00294 std::vector< int > partRanks; 00295 std::vector< int > partLocalIds; 00296 std::vector< int > localIdReverseMap; 00297 }; 00298 00299 /**\brief Create mesh for use in parallel tests */ 00300 int create_mesh( const char* filename, int num_parts ); 00301 00302 int create_mesh_in_memory( int rank, int size, iMesh_Instance imesh, iMeshP_PartitionHandle& prtn, PartMap& map ); 00303 00304 /**\brief get unique identifier for each vertex */ 00305 int vertex_tag( iMesh_Instance imesh, iBase_EntityHandle vertex, int& tag ); 00306 00307 int get_local_parts( iMesh_Instance instance, 00308 iMeshP_PartitionHandle prtn, 00309 std::vector< iMeshP_PartHandle >& handles, 00310 std::vector< iMeshP_Part >* ids = 0 ) 00311 { 00312 iMeshP_PartHandle* arr = 0; 00313 int ierr, alloc = 0, size; 00314 iMeshP_getLocalParts( instance, prtn, &arr, &alloc, &size, &ierr );CHKERR; 00315 handles.resize( size ); 00316 std::copy( arr, arr + size, handles.begin() ); 00317 free( arr ); 00318 if( !ids ) return iBase_SUCCESS; 00319 00320 ids->resize( size ); 00321 alloc = size; 00322 iMeshP_Part* ptr = &( *ids )[0]; 00323 iMeshP_getPartIdsFromPartHandlesArr( instance, prtn, &handles[0], handles.size(), &ptr, &alloc, &size, &ierr );CHKERR; 00324 assert( size == (int)ids->size() ); 00325 assert( ptr == &( *ids )[0] ); 00326 return iBase_SUCCESS; 00327 } 00328 00329 static int get_entities( iMesh_Instance imesh, 00330 iBase_EntitySetHandle set, 00331 iBase_EntityType type, 00332 iMesh_EntityTopology topo, 00333 std::vector< iBase_EntityHandle >& entities ) 00334 { 00335 iBase_EntityHandle* array = 0; 00336 int junk = 0, size = 0, err; 00337 iMesh_getEntities( imesh, set, type, topo, &array, &junk, &size, &err ); 00338 if( !err ) 00339 { 00340 entities.clear(); 00341 entities.resize( size ); 00342 std::copy( array, array + size, entities.begin() ); 00343 free( array ); 00344 } 00345 return err; 00346 } 00347 00348 static int get_part_quads_and_verts( iMesh_Instance imesh, 00349 iMeshP_PartHandle part, 00350 std::vector< iBase_EntityHandle >& elems, 00351 std::vector< iBase_EntityHandle >& verts ) 00352 { 00353 int ierr = get_entities( imesh, part, iBase_FACE, iMesh_QUADRILATERAL, elems );CHKERR; 00354 00355 verts.resize( 4 * elems.size() ); 00356 std::vector< int > junk( elems.size() + 1 ); 00357 int junk1 = verts.size(), count, junk2 = junk.size(), junk3; 00358 iBase_EntityHandle* junk4 = &verts[0]; 00359 int* junk5 = &junk[0]; 00360 iMesh_getEntArrAdj( imesh, &elems[0], elems.size(), iBase_VERTEX, &junk4, &junk1, &count, &junk5, &junk2, &junk3, 00361 &ierr );CHKERR; 00362 assert( junk1 == (int)verts.size() ); 00363 assert( count == (int)( 4 * elems.size() ) ); 00364 assert( junk2 == (int)junk.size() ); 00365 assert( junk4 == &verts[0] ); 00366 assert( junk5 == &junk[0] ); 00367 std::sort( verts.begin(), verts.end() ); 00368 verts.erase( std::unique( verts.begin(), verts.end() ), verts.end() ); 00369 return iBase_SUCCESS; 00370 } 00371 00372 static int get_coords( iMesh_Instance imesh, const iBase_EntityHandle* verts, int num_verts, double* coords ) 00373 { 00374 double* junk1 = coords; 00375 int junk2 = 3 * num_verts; 00376 int junk3; 00377 int ierr; 00378 iMesh_getVtxArrCoords( imesh, verts, num_verts, iBase_INTERLEAVED, &junk1, &junk2, &junk3, &ierr ); 00379 if( iBase_SUCCESS != ierr ) return ierr; 00380 assert( junk1 == coords ); 00381 assert( junk2 == 3 * num_verts ); 00382 assert( junk3 == 3 * num_verts ); 00383 return iBase_SUCCESS; 00384 } 00385 00386 /************************************************************************** 00387 Main Method 00388 **************************************************************************/ 00389 00390 #define RUN_TEST( A ) run_test( &( A ), #A ) 00391 00392 int run_test( int ( *func )( iMesh_Instance, iMeshP_PartitionHandle, const PartMap& ), const char* func_name ) 00393 { 00394 int rank, size, ierr; 00395 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 00396 MPI_Comm_size( MPI_COMM_WORLD, &size ); 00397 iMesh_Instance imesh; 00398 iMesh_newMesh( 0, &imesh, &ierr, 0 ); 00399 PCHECK; 00400 00401 iMeshP_PartitionHandle prtn; 00402 iMeshP_createPartitionAll( imesh, MPI_COMM_WORLD, &prtn, &ierr ); 00403 PCHECK; 00404 00405 PartMap map; 00406 00407 #ifdef MOAB_HAVE_HDF5 00408 if( rank == 0 ) 00409 { 00410 ierr = create_mesh( FILENAME, size ); 00411 } 00412 MPI_Bcast( &ierr, 1, MPI_INT, 0, MPI_COMM_WORLD ); 00413 if( ierr ) 00414 { 00415 if( rank == 0 ) 00416 { 00417 std::cerr << "Failed to create input test file on root processor. Aborting." << std::endl; 00418 } 00419 abort(); 00420 } 00421 00422 ierr = test_load( imesh, prtn, map, size ); 00423 if( ierr ) 00424 { 00425 if( rank == 0 ) 00426 { 00427 std::cerr << "Failed to load input mesh." << std::endl 00428 << "Cannot run further tests." << std::endl 00429 << "ABORTING" << std::endl; 00430 } 00431 abort(); 00432 } 00433 #else 00434 // so we have MPI and no HDF5; in order to run the test we need to create the 00435 // model in memory, and then call sync to resolve shared ents, as if it was read 00436 ierr = create_mesh_in_memory( rank, size, imesh, prtn, map ); 00437 MPI_Bcast( &ierr, 1, MPI_INT, 0, MPI_COMM_WORLD ); 00438 if( ierr ) 00439 { 00440 if( rank == 0 ) 00441 { 00442 std::cerr << "Failed to create mesh. Aborting." << std::endl; 00443 } 00444 abort(); 00445 } 00446 00447 #endif 00448 int result = ( *func )( imesh, prtn, map ); 00449 int is_err = is_any_proc_error( result ); 00450 if( rank == 0 ) 00451 { 00452 if( is_err ) 00453 std::cout << func_name << " : FAILED!!" << std::endl; 00454 else 00455 std::cout << func_name << " : success" << std::endl; 00456 } 00457 00458 iMesh_dtor( imesh, &ierr );CHKERR; 00459 return is_err; 00460 } 00461 00462 int main( int argc, char* argv[] ) 00463 { 00464 MPI_Init( &argc, &argv ); 00465 int size, rank; 00466 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 00467 MPI_Comm_size( MPI_COMM_WORLD, &size ); 00468 00469 if( argc > 2 && !strcmp( argv[1], "-p" ) ) 00470 { 00471 #if !defined( _MSC_VER ) && !defined( __MINGW32__ ) 00472 std::cout << "Processor " << rank << " of " << size << " with PID " << getpid() << std::endl; 00473 std::cout.flush(); 00474 #endif 00475 // loop forever on requested processor, giving the user time 00476 // to attach a debugger. Once the debugger in attached, user 00477 // can change 'pause'. E.g. on gdb do "set var pause = 0" 00478 if( atoi( argv[2] ) == rank ) 00479 { 00480 volatile int pause = 1; 00481 while( pause ) 00482 ; 00483 } 00484 MPI_Barrier( MPI_COMM_WORLD ); 00485 } 00486 00487 int num_errors = 0; 00488 num_errors += RUN_TEST( test_get_partitions ); 00489 num_errors += RUN_TEST( test_get_parts ); 00490 num_errors += RUN_TEST( test_get_by_type ); 00491 num_errors += RUN_TEST( test_get_by_topo ); 00492 num_errors += RUN_TEST( test_part_id_handle ); 00493 num_errors += RUN_TEST( test_part_rank ); 00494 num_errors += RUN_TEST( test_get_neighbors ); 00495 num_errors += RUN_TEST( test_get_part_boundary ); 00496 num_errors += RUN_TEST( test_part_boundary_iter ); 00497 num_errors += RUN_TEST( test_get_adjacencies ); 00498 num_errors += RUN_TEST( test_entity_iterator ); 00499 num_errors += RUN_TEST( test_entity_owner ); 00500 num_errors += RUN_TEST( test_entity_status ); 00501 num_errors += RUN_TEST( test_entity_copy_parts ); 00502 num_errors += RUN_TEST( test_entity_copies ); 00503 num_errors += RUN_TEST( test_push_tag_data_iface ); 00504 num_errors += RUN_TEST( test_push_tag_data_ghost ); 00505 num_errors += RUN_TEST( test_create_ghost_ents ); 00506 num_errors += RUN_TEST( test_exchange_ents ); 00507 00508 // wait until all procs are done before writing summary data 00509 std::cout.flush(); 00510 MPI_Barrier( MPI_COMM_WORLD ); 00511 00512 #ifdef MOAB_HAVE_HDF5 00513 // clean up output file 00514 if( rank == 0 ) remove( FILENAME ); 00515 #endif 00516 00517 if( rank == 0 ) 00518 { 00519 if( !num_errors ) 00520 std::cout << "All tests passed" << std::endl; 00521 else 00522 std::cout << num_errors << " TESTS FAILED!" << std::endl; 00523 } 00524 00525 MPI_Finalize(); 00526 return num_errors; 00527 } 00528 00529 // Create a mesh 00530 // 00531 // 00532 // Groups of four quads will be arranged into parts as follows: 00533 // +------+------+------+------+------+----- 00534 // | | | 00535 // | | | 00536 // + Part 0 + Part 2 + Part 4 00537 // | | | 00538 // | | | 00539 // +------+------+------+------+------+----- 00540 // | | | 00541 // | | | 00542 // + Part 1 + Part 3 + Part 5 00543 // | | | 00544 // | | | 00545 // +------+------+------+------+------+----- 00546 // 00547 // Vertices will be enumerated as follows: 00548 // 1------6-----11-----16-----21-----26----- 00549 // | | | 00550 // | | | 00551 // 2 7 12 17 22 27 00552 // | | | 00553 // | | | 00554 // 3------8-----13-----18-----23-----28----- 00555 // | | | 00556 // | | | 00557 // 4 9 14 19 24 29 00558 // | | | 00559 // | | | 00560 // 5-----10-----15-----20-----25-----30----- 00561 // 00562 // Element IDs will be [4*rank+1,4*rank+5] 00563 template < int size > 00564 struct EHARR 00565 { 00566 iBase_EntityHandle h[size]; 00567 iBase_EntityHandle& operator[]( int i ) 00568 { 00569 return h[i]; 00570 } 00571 operator iBase_EntityHandle*() 00572 { 00573 return h; 00574 } 00575 }; 00576 int create_mesh( const char* filename, int num_parts ) 00577 { 00578 const char* tagname = "GLOBAL_ID"; 00579 int ierr; 00580 00581 iMesh_Instance imesh; 00582 iMesh_newMesh( 0, &imesh, &ierr, 0 );CHKERR; 00583 00584 const int num_full_cols = 2 * ( num_parts / 2 ); 00585 const int need_half_cols = num_parts % 2; 00586 const int num_cols = num_full_cols + 2 * need_half_cols; 00587 const int num_vtx = 5 + 5 * num_cols - 4 * ( num_parts % 2 ); 00588 std::vector< EHARR< 5 > > vertices( num_cols + 1 ); 00589 std::vector< EHARR< 4 > > elements( num_cols ); 00590 std::vector< int > vertex_ids( num_vtx ); 00591 std::vector< iBase_EntityHandle > vertex_list( num_vtx ); 00592 for( int i = 0; i < num_vtx; ++i ) 00593 vertex_ids[i] = i + 1; 00594 00595 // create vertices 00596 int vl_pos = 0; 00597 for( int i = 0; i <= num_cols; ++i ) 00598 { 00599 double coords[15] = { static_cast< double >( i ), 0, 0, static_cast< double >( i ), 1, 0, 00600 static_cast< double >( i ), 2, 0, static_cast< double >( i ), 3, 0, 00601 static_cast< double >( i ), 4, 0 }; 00602 iBase_EntityHandle* ptr = vertices[i]; 00603 const int n = ( num_full_cols == num_cols || i <= num_full_cols ) ? 5 : 3; 00604 int junk1 = n, junk2 = n; 00605 iMesh_createVtxArr( imesh, n, iBase_INTERLEAVED, coords, 3 * n, &ptr, &junk1, &junk2, &ierr );CHKERR; 00606 assert( ptr == vertices[i] ); 00607 assert( junk1 == n ); 00608 assert( junk2 == n ); 00609 for( int j = 0; j < n; ++j ) 00610 vertex_list[vl_pos++] = vertices[i][j]; 00611 } 00612 00613 // create elements 00614 for( int i = 0; i < num_cols; ++i ) 00615 { 00616 iBase_EntityHandle conn[16]; 00617 for( int j = 0; j < 4; ++j ) 00618 { 00619 conn[4 * j] = vertices[i][j]; 00620 conn[4 * j + 1] = vertices[i][j + 1]; 00621 conn[4 * j + 2] = vertices[i + 1][j + 1]; 00622 conn[4 * j + 3] = vertices[i + 1][j]; 00623 } 00624 iBase_EntityHandle* ptr = elements[i]; 00625 const int n = ( i < num_full_cols ) ? 4 : 2; 00626 int junk1 = n, junk2 = n, junk3 = n, junk4 = n; 00627 int stat[4]; 00628 int* ptr2 = stat; 00629 iMesh_createEntArr( imesh, iMesh_QUADRILATERAL, conn, 4 * n, &ptr, &junk1, &junk2, &ptr2, &junk3, &junk4, 00630 &ierr );CHKERR; 00631 assert( ptr == elements[i] ); 00632 assert( junk1 == n ); 00633 assert( junk2 == n ); 00634 assert( ptr2 == stat ); 00635 assert( junk3 == n ); 00636 assert( junk4 == n ); 00637 } 00638 00639 // create partition 00640 iMeshP_PartitionHandle partition; 00641 iMeshP_createPartitionAll( imesh, MPI_COMM_SELF, &partition, &ierr );CHKERR; 00642 for( int i = 0; i < num_parts; ++i ) 00643 { 00644 iMeshP_PartHandle part; 00645 iMeshP_createPart( imesh, partition, &part, &ierr );CHKERR; 00646 iBase_EntityHandle quads[] = { elements[2 * ( i / 2 )][2 * ( i % 2 )], 00647 elements[2 * ( i / 2 ) + 1][2 * ( i % 2 )], 00648 elements[2 * ( i / 2 )][2 * ( i % 2 ) + 1], 00649 elements[2 * ( i / 2 ) + 1][2 * ( i % 2 ) + 1] }; 00650 iMesh_addEntArrToSet( imesh, quads, 4, part, &ierr );CHKERR; 00651 } 00652 00653 // assign global ids to vertices 00654 iBase_TagHandle id_tag = 0; 00655 iMesh_getTagHandle( imesh, tagname, &id_tag, &ierr, strlen( tagname ) ); 00656 if( iBase_SUCCESS == ierr ) 00657 { 00658 int tag_size, tag_type; 00659 iMesh_getTagSizeValues( imesh, id_tag, &tag_size, &ierr );CHKERR; 00660 if( tag_size != 1 ) return iBase_TAG_ALREADY_EXISTS; 00661 iMesh_getTagType( imesh, id_tag, &tag_type, &ierr );CHKERR; 00662 if( tag_type != iBase_INTEGER ) return iBase_TAG_ALREADY_EXISTS; 00663 } 00664 else 00665 { 00666 iMesh_createTag( imesh, tagname, 1, iBase_INTEGER, &id_tag, &ierr, strlen( tagname ) );CHKERR; 00667 } 00668 iMesh_setIntArrData( imesh, &vertex_list[0], num_vtx, id_tag, &vertex_ids[0], num_vtx, &ierr );CHKERR; 00669 00670 // write file 00671 iBase_EntitySetHandle root_set; 00672 iMesh_getRootSet( imesh, &root_set, &ierr ); 00673 iMeshP_saveAll( imesh, partition, root_set, filename, 0, &ierr, strlen( filename ), 0 );CHKERR; 00674 00675 iMesh_dtor( imesh, &ierr );CHKERR; 00676 00677 return 0; 00678 } 00679 int create_mesh_in_memory( int rank, 00680 int num_parts, 00681 iMesh_Instance imesh, 00682 iMeshP_PartitionHandle& partition, 00683 PartMap& map ) 00684 { 00685 const char* tagname = "GLOBAL_ID"; 00686 int ierr; 00687 00688 const int num_cols = 2; 00689 const int num_vtx = 9; 00690 // we are on the top or botton row 00691 int bottom = rank % 2; // 0 2 00692 // 1 3 00693 std::vector< EHARR< 3 > > vertices( 3 ); 00694 std::vector< EHARR< 2 > > elements( 2 ); // 4 elements per process 00695 std::vector< int > vertex_ids( num_vtx ); 00696 std::vector< iBase_EntityHandle > vertex_list( num_vtx ); 00697 int start = 1 + 2 * bottom + 10 * ( rank / 2 ); 00698 00699 for( int i = 0; i < 3; ++i ) 00700 for( int j = 0; j < 3; ++j ) 00701 { 00702 vertex_ids[i + 3 * j] = start + i + 5 * j; 00703 } 00704 00705 // create vertices 00706 int vl_pos = 0; 00707 int startI = 2 * ( rank / 2 ); // so it will be 0, 0, 2, 2, ...) 00708 for( int i = 0; i <= 2; ++i ) 00709 { 00710 double coords[9] = { 00711 static_cast< double >( i + startI ), 2. * bottom, 0, 00712 static_cast< double >( i + startI ), 1 + 2. * bottom, 0, 00713 static_cast< double >( i + startI ), 2 + 2. * bottom, 0, 00714 }; 00715 iBase_EntityHandle* ptr = vertices[i]; 00716 const int n = 3; 00717 int junk1 = n, junk2 = n; 00718 iMesh_createVtxArr( imesh, n, iBase_INTERLEAVED, coords, 3 * n, &ptr, &junk1, &junk2, &ierr );CHKERR; 00719 assert( ptr == vertices[i] ); 00720 assert( junk1 == n ); 00721 assert( junk2 == n ); 00722 for( int j = 0; j < n; ++j ) 00723 vertex_list[vl_pos++] = vertices[i][j]; 00724 } 00725 00726 // create elements 00727 for( int i = 0; i < num_cols; ++i ) 00728 { 00729 iBase_EntityHandle conn[8]; 00730 for( int j = 0; j < 2; ++j ) 00731 { 00732 conn[4 * j] = vertices[i][j]; 00733 conn[4 * j + 1] = vertices[i][j + 1]; 00734 conn[4 * j + 2] = vertices[i + 1][j + 1]; 00735 conn[4 * j + 3] = vertices[i + 1][j]; 00736 } 00737 iBase_EntityHandle* ptr = elements[i]; 00738 const int n = 2; 00739 int junk1 = n, junk2 = n, junk3 = n, junk4 = n; 00740 int stat[4]; 00741 int* ptr2 = stat; 00742 iMesh_createEntArr( imesh, iMesh_QUADRILATERAL, conn, 4 * n, &ptr, &junk1, &junk2, &ptr2, &junk3, &junk4, 00743 &ierr );CHKERR; 00744 assert( ptr == elements[i] ); 00745 assert( junk1 == n ); 00746 assert( junk2 == n ); 00747 assert( ptr2 == stat ); 00748 assert( junk3 == n ); 00749 assert( junk4 == n ); 00750 } 00751 00752 // create partition 00753 iMeshP_createPartitionAll( imesh, MPI_COMM_WORLD, &partition, &ierr );CHKERR; 00754 00755 iMeshP_PartHandle part; 00756 iMeshP_createPart( imesh, partition, &part, &ierr );CHKERR; 00757 iBase_EntityHandle quads[] = { elements[0][0], elements[0][1], elements[1][0], elements[1][1] }; 00758 iMesh_addEntArrToSet( imesh, quads, 4, part, &ierr );CHKERR; 00759 00760 // assign global ids to vertices 00761 iBase_TagHandle id_tag = 0; 00762 iMesh_getTagHandle( imesh, tagname, &id_tag, &ierr, strlen( tagname ) ); 00763 if( iBase_SUCCESS == ierr ) 00764 { 00765 int tag_size, tag_type; 00766 iMesh_getTagSizeValues( imesh, id_tag, &tag_size, &ierr );CHKERR; 00767 if( tag_size != 1 ) return iBase_TAG_ALREADY_EXISTS; 00768 iMesh_getTagType( imesh, id_tag, &tag_type, &ierr );CHKERR; 00769 if( tag_type != iBase_INTEGER ) return iBase_TAG_ALREADY_EXISTS; 00770 } 00771 else 00772 { 00773 iMesh_createTag( imesh, tagname, 1, iBase_INTEGER, &id_tag, &ierr, strlen( tagname ) );CHKERR; 00774 } 00775 iMesh_setIntArrData( imesh, &vertex_list[0], num_vtx, id_tag, &vertex_ids[0], num_vtx, &ierr );CHKERR; 00776 00777 // some mesh sync 00778 iMeshP_syncPartitionAll( imesh, partition, &ierr );CHKERR; 00779 iMeshP_syncMeshAll( imesh, partition, &ierr );CHKERR; 00780 00781 ierr = map.build_map( imesh, partition, num_parts );CHKERR; 00782 return 0; 00783 } 00784 // generate unique for each vertex from coordinates. 00785 // Assume integer coordinate values with x in [0,inf] and y in [0,4] 00786 // as generated by create_mean(..). 00787 int vertex_tag( iMesh_Instance imesh, iBase_EntityHandle vertex, int& tag ) 00788 { 00789 int ierr; 00790 double x, y, z; 00791 iMesh_getVtxCoord( imesh, vertex, &x, &y, &z, &ierr );CHKERR; 00792 00793 int xc = (int)round( x ); 00794 int yc = (int)round( y ); 00795 tag = 5 * xc + yc + 1; 00796 return ierr; 00797 } 00798 00799 /************************************************************************** 00800 Test Implementations 00801 **************************************************************************/ 00802 00803 int test_load( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, PartMap& map, int proc_size ) 00804 { 00805 int ierr; 00806 00807 iBase_EntitySetHandle root_set; 00808 iMesh_getRootSet( imesh, &root_set, &ierr ); 00809 const char* opt = "moab:PARTITION=PARALLEL_PARTITION"; 00810 iMeshP_loadAll( imesh, prtn, root_set, FILENAME, opt, &ierr, strlen( FILENAME ), strlen( opt ) ); 00811 PCHECK; 00812 00813 ierr = map.build_map( imesh, prtn, proc_size );CHKERR; 00814 return iBase_SUCCESS; 00815 } 00816 00817 /**\brief Test partition query methods 00818 * 00819 * Test: 00820 * - iMeshP_getPartitionComm 00821 * - iMeshP_getNumPartitions 00822 * - iMeshP_getPartitions 00823 */ 00824 int test_get_partitions( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& ) 00825 { 00826 int ierr; 00827 00828 // test iMeshP_getPartitionCom 00829 MPI_Comm comm = MPI_COMM_SELF; 00830 iMeshP_getPartitionComm( imesh, prtn, &comm, &ierr ); 00831 PCHECK; 00832 ASSERT( comm == MPI_COMM_WORLD ); 00833 00834 // test iMeshP_getPartitions 00835 iMeshP_PartitionHandle* array = 0; 00836 int alloc = 0, size = -1; 00837 iMeshP_getPartitions( imesh, &array, &alloc, &size, &ierr ); 00838 PCHECK; 00839 ASSERT( array != 0 ); 00840 ASSERT( alloc == size ); 00841 ASSERT( size > 0 ); 00842 int idx = std::find( array, array + size, prtn ) - array; 00843 free( array ); 00844 ASSERT( idx < size ); 00845 00846 // test iMesP_getNumPartitions 00847 int size2 = -1; 00848 iMeshP_getNumPartitions( imesh, &size2, &ierr ); 00849 PCHECK; 00850 ASSERT( size2 == size ); 00851 return 0; 00852 } 00853 00854 /**\brief Test part quyery methods 00855 * 00856 * Test: 00857 * - iMeshP_getNumGlobalParts 00858 * - iMeshP_getNumLocalParts 00859 * - iMeshP_getLocalParts 00860 */ 00861 int test_get_parts( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 00862 { 00863 int size, rank, ierr; 00864 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 00865 MPI_Comm_size( MPI_COMM_WORLD, &size ); 00866 00867 int num_part_g; 00868 iMeshP_getNumGlobalParts( imesh, prtn, &num_part_g, &ierr ); 00869 PCHECK; 00870 ASSERT( num_part_g == map.num_parts() ); 00871 00872 int num_part_l; 00873 iMeshP_getNumLocalParts( imesh, prtn, &num_part_l, &ierr ); 00874 PCHECK; 00875 ASSERT( num_part_l == map.count_from_rank( rank ) ); 00876 00877 std::vector< iMeshP_PartHandle > parts( num_part_l ); 00878 iMeshP_PartHandle* ptr = &parts[0]; 00879 int junk1 = num_part_l, count = -1; 00880 iMeshP_getLocalParts( imesh, prtn, &ptr, &junk1, &count, &ierr ); 00881 PCHECK; 00882 assert( ptr == &parts[0] ); 00883 assert( junk1 == num_part_l ); 00884 ASSERT( count == num_part_l ); 00885 00886 return iBase_SUCCESS; 00887 } 00888 00889 static int test_get_by_type_topo_all( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, bool test_type, int num_parts ) 00890 { 00891 // calculate number of quads and vertices in entire mesh 00892 // from number of parts (see create_mesh(..) function.) 00893 const int expected_global_quad_count = 4 * num_parts; 00894 const int num_col = 2 * ( num_parts / 2 + num_parts % 2 ); 00895 const int expected_global_vtx_count = num_parts == 1 ? 9 : num_parts % 2 ? 1 + 5 * num_col : 5 + 5 * num_col; 00896 00897 // test getNumOf*All for root set 00898 int ierr, count; 00899 iBase_EntitySetHandle root; 00900 iMesh_getRootSet( imesh, &root, &ierr ); 00901 if( test_type ) 00902 iMeshP_getNumOfTypeAll( imesh, prtn, root, iBase_VERTEX, &count, &ierr ); 00903 else 00904 iMeshP_getNumOfTopoAll( imesh, prtn, root, iMesh_POINT, &count, &ierr ); 00905 PCHECK; 00906 ASSERT( count == expected_global_vtx_count ); 00907 if( test_type ) 00908 iMeshP_getNumOfTypeAll( imesh, prtn, root, iBase_FACE, &count, &ierr ); 00909 else 00910 iMeshP_getNumOfTopoAll( imesh, prtn, root, iMesh_QUADRILATERAL, &count, &ierr ); 00911 PCHECK; 00912 ASSERT( count == expected_global_quad_count ); 00913 00914 // create an entity set containing half of the quads 00915 std::vector< iBase_EntityHandle > all_quads, half_quads; 00916 ierr = get_entities( imesh, root, iBase_FACE, iMesh_QUADRILATERAL, all_quads ); 00917 assert( 0 == all_quads.size() % 2 ); 00918 half_quads.resize( all_quads.size() / 2 ); 00919 for( size_t i = 0; i < all_quads.size() / 2; ++i ) 00920 half_quads[i] = all_quads[2 * i]; 00921 iBase_EntitySetHandle set; 00922 iMesh_createEntSet( imesh, 1, &set, &ierr );CHKERR; 00923 iMesh_addEntArrToSet( imesh, &half_quads[0], half_quads.size(), set, &ierr );CHKERR; 00924 00925 // test getNumOf*All with defined set 00926 if( test_type ) 00927 iMeshP_getNumOfTypeAll( imesh, prtn, set, iBase_VERTEX, &count, &ierr ); 00928 else 00929 iMeshP_getNumOfTopoAll( imesh, prtn, set, iMesh_POINT, &count, &ierr ); 00930 PCHECK; 00931 ASSERT( count == 0 ); 00932 if( test_type ) 00933 iMeshP_getNumOfTypeAll( imesh, prtn, set, iBase_FACE, &count, &ierr ); 00934 else 00935 iMeshP_getNumOfTopoAll( imesh, prtn, set, iMesh_QUADRILATERAL, &count, &ierr ); 00936 PCHECK; 00937 ASSERT( count == expected_global_quad_count / 2 ); 00938 00939 return 0; 00940 } 00941 00942 static int test_get_by_type_topo_local( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, bool test_type ) 00943 { 00944 int ierr; 00945 iBase_EntitySetHandle root; 00946 iMesh_getRootSet( imesh, &root, &ierr ); 00947 00948 // select a single part 00949 std::vector< iMeshP_PartHandle > parts; 00950 ierr = get_local_parts( imesh, prtn, parts );CHKERR; 00951 iMeshP_PartHandle part = parts.front(); 00952 00953 // get the entities contained in the part 00954 std::vector< iBase_EntityHandle > part_quads, part_all; 00955 ierr = get_entities( imesh, part, iBase_FACE, iMesh_QUADRILATERAL, part_quads );CHKERR; 00956 ierr = get_entities( imesh, part, iBase_ALL_TYPES, iMesh_ALL_TOPOLOGIES, part_all );CHKERR; 00957 00958 // compare local counts (using root set) 00959 00960 int count; 00961 if( test_type ) 00962 iMeshP_getNumOfType( imesh, prtn, part, root, iBase_FACE, &count, &ierr ); 00963 else 00964 iMeshP_getNumOfTopo( imesh, prtn, part, root, iMesh_QUADRILATERAL, &count, &ierr );CHKERR; 00965 ASSERT( count == (int)part_quads.size() ); 00966 00967 if( test_type ) 00968 iMeshP_getNumOfType( imesh, prtn, part, root, iBase_ALL_TYPES, &count, &ierr ); 00969 else 00970 iMeshP_getNumOfTopo( imesh, prtn, part, root, iMesh_ALL_TOPOLOGIES, &count, &ierr );CHKERR; 00971 ASSERT( count == (int)part_all.size() ); 00972 00973 // compare local contents (using root set) 00974 00975 iBase_EntityHandle* ptr = 0; 00976 int num_ent, junk1 = 0; 00977 iMeshP_getEntities( imesh, prtn, part, root, test_type ? iBase_FACE : iBase_ALL_TYPES, 00978 test_type ? iMesh_ALL_TOPOLOGIES : iMesh_QUADRILATERAL, &ptr, &junk1, &num_ent, &ierr );CHKERR; 00979 std::vector< iBase_EntityHandle > act_quads( ptr, ptr + num_ent ); 00980 free( ptr ); 00981 junk1 = num_ent = 0; 00982 ptr = 0; 00983 iMeshP_getEntities( imesh, prtn, part, root, iBase_ALL_TYPES, iMesh_ALL_TOPOLOGIES, &ptr, &junk1, &num_ent, &ierr );CHKERR; 00984 std::vector< iBase_EntityHandle > act_all( ptr, ptr + num_ent ); 00985 free( ptr ); 00986 std::sort( part_quads.begin(), part_quads.end() ); 00987 std::sort( part_all.begin(), part_all.end() ); 00988 std::sort( act_quads.begin(), act_quads.end() ); 00989 std::sort( act_all.begin(), act_all.end() ); 00990 ASSERT( part_quads == act_quads ); 00991 ASSERT( part_all == act_all ); 00992 00993 // create an entity set containing half of the quads from the part 00994 std::vector< iBase_EntityHandle > half_quads( part_quads.size() / 2 ); 00995 for( size_t i = 0; i < half_quads.size(); ++i ) 00996 half_quads[i] = part_quads[2 * i]; 00997 iBase_EntitySetHandle set; 00998 iMesh_createEntSet( imesh, 1, &set, &ierr );CHKERR; 00999 iMesh_addEntArrToSet( imesh, &half_quads[0], half_quads.size(), set, &ierr );CHKERR; 01000 01001 // check if there exists any quads not in the part that we 01002 // can add to the set 01003 std::vector< iBase_EntityHandle > all_quads, other_quads; 01004 ierr = get_entities( imesh, root, iBase_FACE, iMesh_QUADRILATERAL, all_quads );CHKERR; 01005 std::sort( all_quads.begin(), all_quads.end() ); 01006 std::sort( part_quads.begin(), part_quads.end() ); 01007 std::set_difference( all_quads.begin(), all_quads.end(), part_quads.begin(), part_quads.end(), 01008 std::back_inserter( other_quads ) ); 01009 iMesh_addEntArrToSet( imesh, &other_quads[0], other_quads.size(), set, &ierr );CHKERR; 01010 01011 // compare local counts (using non-root set) 01012 01013 if( test_type ) 01014 iMeshP_getNumOfType( imesh, prtn, part, set, iBase_FACE, &count, &ierr ); 01015 else 01016 iMeshP_getNumOfTopo( imesh, prtn, part, set, iMesh_QUADRILATERAL, &count, &ierr );CHKERR; 01017 ASSERT( count == (int)half_quads.size() ); 01018 01019 if( test_type ) 01020 iMeshP_getNumOfType( imesh, prtn, part, set, iBase_VERTEX, &count, &ierr ); 01021 else 01022 iMeshP_getNumOfTopo( imesh, prtn, part, set, iMesh_POINT, &count, &ierr );CHKERR; 01023 ASSERT( count == 0 ); 01024 01025 // compare local contents (using non-root set) 01026 01027 junk1 = 0; 01028 num_ent = 0; 01029 ptr = 0; 01030 iMeshP_getEntities( imesh, prtn, part, set, test_type ? iBase_FACE : iBase_ALL_TYPES, 01031 test_type ? iMesh_ALL_TOPOLOGIES : iMesh_QUADRILATERAL, &ptr, &junk1, &num_ent, &ierr );CHKERR; 01032 act_quads.resize( num_ent ); 01033 std::copy( ptr, ptr + num_ent, act_quads.begin() ); 01034 free( ptr ); 01035 std::sort( half_quads.begin(), half_quads.end() ); 01036 std::sort( act_quads.begin(), act_quads.end() ); 01037 ASSERT( act_quads == half_quads ); 01038 01039 return iBase_SUCCESS; 01040 } 01041 01042 /**\brief Test query by entity type 01043 * 01044 * Test: 01045 * - iMeshP_getNumOfTypeAll 01046 * - iMeshP_getNumOfType 01047 * - iMeshP_getEntities 01048 * - 01049 */ 01050 int test_get_by_type( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 01051 { 01052 int ierr; 01053 ierr = test_get_by_type_topo_all( imesh, prtn, true, map.num_parts() ); 01054 PCHECK; 01055 ierr = test_get_by_type_topo_local( imesh, prtn, true ); 01056 PCHECK; 01057 return 0; 01058 } 01059 01060 /**\brief Test query by entity topology 01061 * 01062 * Test: 01063 * - iMeshP_getNumOfTopoAll 01064 * - iMeshP_getNumOfTopo 01065 * - iMeshP_getEntities 01066 * - 01067 */ 01068 int test_get_by_topo( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 01069 { 01070 int ierr; 01071 ierr = test_get_by_type_topo_all( imesh, prtn, false, map.num_parts() ); 01072 PCHECK; 01073 ierr = test_get_by_type_topo_local( imesh, prtn, false ); 01074 PCHECK; 01075 return 0; 01076 } 01077 01078 /**\brief Test mapping from part id to part handle 01079 * 01080 * Test: 01081 * - iMeshP_getPartIdFromPartHandle 01082 * - iMeshP_getPartIdsFromPartHandlesArr 01083 * - iMeshP_getPartHandleFromPartId 01084 * - iMeshP_getPartHandlesFromPartsIdsArr 01085 */ 01086 int test_part_id_handle( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 01087 { 01088 // get local part ids 01089 int rank, ierr; 01090 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 01091 std::vector< iMeshP_Part > ids; 01092 map.part_id_from_rank( rank, ids ); 01093 01094 // check single-part functions and build list of part handles 01095 std::vector< iMeshP_PartHandle > handles( ids.size() ); 01096 size_t i; 01097 for( i = 0; i < ids.size(); ++i ) 01098 { 01099 iMeshP_getPartHandleFromPartId( imesh, prtn, ids[i], &handles[i], &ierr );CHKERR; 01100 iMeshP_Part id; 01101 iMeshP_getPartIdFromPartHandle( imesh, prtn, handles[i], &id, &ierr );CHKERR; 01102 if( id != ids[i] ) break; 01103 } 01104 ASSERT( i == ids.size() ); 01105 01106 // test iMeshP_getPartIdsFromPartHandlesArr 01107 std::vector< iMeshP_Part > ids2( ids.size() ); 01108 int junk1 = ids.size(), junk2 = 0; 01109 iMeshP_Part* ptr = &ids2[0]; 01110 iMeshP_getPartIdsFromPartHandlesArr( imesh, prtn, &handles[0], handles.size(), &ptr, &junk1, &junk2, &ierr ); 01111 PCHECK; 01112 ASSERT( ptr == &ids2[0] ); 01113 ASSERT( junk2 == (int)ids2.size() ); 01114 ASSERT( ids == ids2 ); 01115 01116 // test iMeshP_getPartHandlesFromPartsIdsArr 01117 std::vector< iMeshP_PartHandle > handles2( handles.size() ); 01118 junk1 = handles.size(); 01119 junk2 = 0; 01120 iMeshP_PartHandle* ptr2 = &handles2[0]; 01121 iMeshP_getPartHandlesFromPartsIdsArr( imesh, prtn, &ids[0], ids.size(), &ptr2, &junk1, &junk2, &ierr ); 01122 PCHECK; 01123 ASSERT( ptr2 == &handles2[0] ); 01124 ASSERT( junk2 == (int)handles2.size() ); 01125 ASSERT( handles == handles2 ); 01126 01127 return 0; 01128 } 01129 01130 /**\brief Test get part rank 01131 * 01132 * Tests: 01133 * - iMeshP_getRankOfPart 01134 * - iMeshP_getRankOfPartArr 01135 */ 01136 int test_part_rank( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 01137 { 01138 int ierr = 0, rank; 01139 std::vector< iMeshP_Part > invalid, failed; 01140 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 01141 01142 // test iMeshP_getRankOfPart 01143 for( size_t i = 0; i < map.get_parts().size(); ++i ) 01144 { 01145 int pr; 01146 iMeshP_getRankOfPart( imesh, prtn, map.get_parts()[i], &pr, &ierr ); 01147 if( iBase_SUCCESS != ierr ) 01148 failed.push_back( map.get_parts()[i] ); 01149 else if( pr != map.get_ranks()[i] ) 01150 invalid.push_back( map.get_parts()[i] ); 01151 } 01152 if( !failed.empty() ) 01153 { 01154 std::cerr << "Processor " << rank << ": iMeshP_getRankOfPart failed for " << failed.size() << " parts." 01155 << std::endl; 01156 ierr = iBase_FAILURE; 01157 } 01158 if( !invalid.empty() ) 01159 { 01160 std::cerr << "Processor " << rank << ": iMeshP_getRankOfPart was incorrect for " << invalid.size() << " parts." 01161 << std::endl; 01162 ierr = iBase_FAILURE; 01163 } 01164 PCHECK; 01165 01166 // test iMeshP_getRankOfPartArr 01167 std::vector< int > ranks( map.get_parts().size() ); 01168 int junk1 = ranks.size(), junk2, *ptr = &ranks[0]; 01169 iMeshP_getRankOfPartArr( imesh, prtn, &map.get_parts()[0], map.get_parts().size(), &ptr, &junk1, &junk2, &ierr ); 01170 PCHECK; 01171 assert( ptr == &ranks[0] ); 01172 assert( junk1 == (int)ranks.size() ); 01173 ASSERT( junk2 == (int)ranks.size() ); 01174 for( size_t i = 0; i < map.get_parts().size(); ++i ) 01175 { 01176 if( ranks[i] != map.get_ranks()[i] ) invalid.push_back( map.get_parts()[i] ); 01177 } 01178 if( !invalid.empty() ) 01179 { 01180 std::cerr << "Processor " << rank << ": iMeshP_getRankOfPartArr was incorrect for " << invalid.size() 01181 << " parts." << std::endl; 01182 ierr = iBase_FAILURE; 01183 } 01184 PCHECK; 01185 01186 return 0; 01187 } 01188 01189 // see create_mesh(..) 01190 static void get_part_neighbors( int logical_part_id, int num_parts, int neighbors[5], int& num_neighbors ) 01191 { 01192 num_neighbors = 0; 01193 if( logical_part_id + 1 < num_parts ) neighbors[num_neighbors++] = logical_part_id + 1; 01194 if( logical_part_id + 2 < num_parts ) neighbors[num_neighbors++] = logical_part_id + 2; 01195 if( logical_part_id % 2 ) 01196 { 01197 neighbors[num_neighbors++] = logical_part_id - 1; 01198 if( logical_part_id > 2 ) 01199 { 01200 neighbors[num_neighbors++] = logical_part_id - 3; 01201 neighbors[num_neighbors++] = logical_part_id - 2; 01202 } 01203 } 01204 else 01205 { 01206 if( logical_part_id + 3 < num_parts ) neighbors[num_neighbors++] = logical_part_id + 3; 01207 if( logical_part_id > 1 ) 01208 { 01209 neighbors[num_neighbors++] = logical_part_id - 1; 01210 neighbors[num_neighbors++] = logical_part_id - 2; 01211 } 01212 } 01213 } 01214 01215 /**\brief Test querying of part neighbors 01216 * 01217 * Test: 01218 * - iMeshP_getNumPartNbors 01219 * - iMeshP_getNumPartNborsArr 01220 * - iMeshP_getPartNbors 01221 * - iMeshP_getPartNborsArr 01222 */ 01223 int test_get_neighbors( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 01224 { 01225 int ierr, rank; 01226 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 01227 01228 std::vector< iMeshP_Part > local_parts; 01229 map.part_id_from_rank( rank, local_parts ); 01230 01231 // get handles for local parts 01232 std::vector< iMeshP_PartHandle > handles( local_parts.size() ); 01233 iMeshP_PartHandle* ptr = &handles[0]; 01234 int junk1 = handles.size(), junk2 = 0; 01235 iMeshP_getPartHandlesFromPartsIdsArr( imesh, prtn, &local_parts[0], local_parts.size(), &ptr, &junk1, &junk2, 01236 &ierr ); 01237 PCHECK; 01238 assert( ptr == &handles[0] ); 01239 assert( junk2 == (int)handles.size() ); 01240 01241 // get logical ids for local parts 01242 std::vector< int > logical_ids; 01243 map.local_id_from_rank( rank, logical_ids ); 01244 01245 // get neighbors for each local part 01246 std::vector< std::vector< iMeshP_Part > > neighbors( logical_ids.size() ); 01247 for( size_t i = 0; i < logical_ids.size(); ++i ) 01248 { 01249 int logical_neighbors[5], num_neighbors; 01250 get_part_neighbors( logical_ids[i], map.num_parts(), logical_neighbors, num_neighbors ); 01251 neighbors[i].resize( num_neighbors ); 01252 for( int j = 0; j < num_neighbors; ++j ) 01253 neighbors[i][j] = map.part_id_from_local_id( logical_neighbors[j] ); 01254 std::sort( neighbors[i].begin(), neighbors[i].end() ); 01255 } 01256 01257 // test iMeshP_getNumPartNbors 01258 std::vector< iMeshP_Part > invalid, failed; 01259 for( size_t i = 0; i < local_parts.size(); ++i ) 01260 { 01261 int count; 01262 iMeshP_getNumPartNbors( imesh, prtn, handles[i], iBase_VERTEX, &count, &ierr ); 01263 if( ierr ) 01264 failed.push_back( local_parts[i] ); 01265 else if( count != (int)neighbors[i].size() ) 01266 invalid.push_back( local_parts[i] ); 01267 } 01268 if( !failed.empty() ) 01269 { 01270 std::cerr << "Processor " << rank << ": iMeshP_getNumPartNbors failed for " << failed.size() << " parts." 01271 << std::endl; 01272 ierr = iBase_FAILURE; 01273 PCHECK; 01274 } 01275 if( !invalid.empty() ) 01276 { 01277 std::cerr << "Processor " << rank << ": iMeshP_getNumPartNbors was incorrect for " << invalid.size() 01278 << " parts." << std::endl; 01279 ierr = iBase_FAILURE; 01280 PCHECK; 01281 } 01282 01283 // test iMeshP_getPartNbors 01284 ierr = 0; 01285 for( size_t i = 0; i < local_parts.size(); ++i ) 01286 { 01287 int count, junk = 0, another_count; 01288 iMeshP_Part* list = 0; 01289 iMeshP_getPartNbors( imesh, prtn, handles[i], iBase_VERTEX, &another_count, &list, &junk, &count, &ierr ); 01290 assert( count == another_count ); 01291 if( ierr ) 01292 failed.push_back( local_parts[i] ); 01293 else 01294 { 01295 std::sort( list, list + count ); 01296 std::vector< iMeshP_Part > cpy( list, list + count ); 01297 if( cpy != neighbors[i] ) invalid.push_back( local_parts[i] ); 01298 free( list ); 01299 } 01300 } 01301 if( !failed.empty() ) 01302 { 01303 std::cerr << "Processor " << rank << ": iMeshP_getPartNbors failed for " << failed.size() << " parts." 01304 << std::endl; 01305 ierr = iBase_FAILURE; 01306 } 01307 if( !invalid.empty() ) 01308 { 01309 std::cerr << "Processor " << rank << ": iMeshP_getPartNbors was incorrect for " << invalid.size() << " parts." 01310 << std::endl; 01311 ierr = iBase_FAILURE; 01312 } 01313 PCHECK; 01314 01315 // test iMeshP_getNumPartNborsArr 01316 std::vector< int > count_vect( handles.size() ); 01317 int* count_arr = &count_vect[0]; 01318 junk1 = handles.size(); 01319 iMeshP_getNumPartNborsArr( imesh, prtn, &handles[0], handles.size(), iBase_VERTEX, &count_arr, &junk1, &junk2, 01320 &ierr ); 01321 PCHECK; 01322 assert( count_arr == &count_vect[0] ); 01323 assert( junk2 == (int)handles.size() ); 01324 for( size_t i = 0; i < local_parts.size(); ++i ) 01325 { 01326 if( count_arr[i] != (int)neighbors[i].size() ) invalid.push_back( local_parts[i] ); 01327 } 01328 if( !invalid.empty() ) 01329 { 01330 std::cerr << "Processor " << rank << ": iMeshP_getNumPartNborsArr was incorrect for " << invalid.size() 01331 << " parts." << std::endl; 01332 ierr = iBase_FAILURE; 01333 } 01334 PCHECK; 01335 01336 // test iMeshP_getPartNborsArr 01337 iMeshP_Part* nbor_arr = 0; 01338 junk1 = handles.size(), junk2 = 0; 01339 int junk3 = 0, nbor_size; 01340 iMeshP_getPartNborsArr( imesh, prtn, &handles[0], handles.size(), iBase_VERTEX, &count_arr, &junk1, &junk2, 01341 &nbor_arr, &junk3, &nbor_size, &ierr ); 01342 PCHECK; 01343 assert( count_arr == &count_vect[0] ); 01344 assert( junk2 == (int)handles.size() ); 01345 std::vector< iMeshP_Part > all_nbors( nbor_arr, nbor_arr + nbor_size ); 01346 free( nbor_arr ); 01347 std::vector< iMeshP_Part >::iterator j = all_nbors.begin(); 01348 bool bad_length = false; 01349 for( size_t i = 0; i < local_parts.size(); ++i ) 01350 { 01351 if( all_nbors.end() - j > count_arr[i] ) 01352 { 01353 bad_length = true; 01354 break; 01355 } 01356 if( count_arr[i] != (int)neighbors[i].size() ) 01357 { 01358 invalid.push_back( local_parts[i] ); 01359 } 01360 else 01361 { 01362 std::vector< iMeshP_Part >::iterator e = j + count_arr[i]; 01363 std::sort( j, e ); 01364 if( !std::equal( j, e, neighbors[i].begin() ) ) invalid.push_back( local_parts[i] ); 01365 } 01366 } 01367 if( bad_length ) 01368 { 01369 std::cerr << "Processor " << rank << ": iMeshP_getPartNborsArr had inconsistent result array lengths." 01370 << std::endl; 01371 ierr = iBase_FAILURE; 01372 } 01373 if( !invalid.empty() ) 01374 { 01375 std::cerr << "Processor " << rank << ": iMeshP_getPartNborsArr was incorrect for " << invalid.size() 01376 << " parts." << std::endl; 01377 ierr = iBase_FAILURE; 01378 } 01379 PCHECK; 01380 01381 return 0; 01382 } 01383 01384 // Determine the expected vertices on the interface between two parts. 01385 // Returns no vertices for non-adjacient parts and fails if both parts 01386 // are the same. 01387 // See create_mesh(..) for the assumed mesh. 01388 static int interface_verts( iMesh_Instance imesh, 01389 iMeshP_PartitionHandle prtn, 01390 iMeshP_PartHandle local_part, 01391 iMeshP_Part other_part, 01392 const PartMap& map, 01393 std::vector< iBase_EntityHandle >& vtx_handles ) 01394 { 01395 int ierr, rank; 01396 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 01397 01398 iMeshP_Part local_id; 01399 iMeshP_getPartIdFromPartHandle( imesh, prtn, local_part, &local_id, &ierr );CHKERR; 01400 01401 const int local_logical = map.local_id_from_part_id( local_id ); 01402 const int other_logical = map.local_id_from_part_id( other_part ); 01403 01404 // get grid of local vertices 01405 01406 iBase_EntityHandle verts[3][3]; 01407 const double xbase = ( local_id / 2 ) * 2; 01408 const double ybase = ( local_id % 2 ) * 2; 01409 01410 // get quads in partition 01411 iBase_EntityHandle quads[4], *ptr = quads; 01412 int junk1 = 4, junk2; 01413 iMesh_getEntities( imesh, local_part, iBase_FACE, iMesh_QUADRILATERAL, &ptr, &junk1, &junk2, &ierr );CHKERR; 01414 assert( ptr == quads ); 01415 assert( junk1 == 4 ); 01416 assert( junk2 == 4 ); 01417 01418 // get vertices in quads 01419 iBase_EntityHandle conn[16]; 01420 int offsets[5], *off_ptr = offsets, junk3 = 5, junk4; 01421 ptr = conn; 01422 junk1 = 16; 01423 iMesh_getEntArrAdj( imesh, quads, 4, iBase_VERTEX, &ptr, &junk1, &junk2, &off_ptr, &junk3, &junk4, &ierr );CHKERR; 01424 assert( ptr == conn ); 01425 assert( junk1 == 16 ); 01426 assert( junk2 == 16 ); 01427 assert( off_ptr == offsets ); 01428 assert( junk3 == 5 ); 01429 assert( junk4 == 5 ); 01430 01431 // make unique vertex list 01432 std::sort( conn, conn + 16 ); 01433 const int num_vtx = std::unique( conn, conn + 16 ) - conn; 01434 assert( 9 == num_vtx ); 01435 01436 // get vertex coords 01437 std::vector< double > coords( 27 ); 01438 ierr = get_coords( imesh, conn, 9, &coords[0] );CHKERR; 01439 01440 // use vertex coords to determine logical position 01441 for( int i = 0; i < num_vtx; ++i ) 01442 { 01443 int x = (int)round( coords[3 * i] - xbase ); 01444 int y = (int)round( coords[3 * i + 1] - ybase ); 01445 if( x < 0 || x > 2 || y < 0 || y > 2 ) 01446 { 01447 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01448 << " Invalid vertex coordinate: (" << coords[3 * i] << ", " << coords[3 * i + 1] << ", " 01449 << coords[3 * i + 2] << ")" << std::endl 01450 << " For logical partition " << local_id << std::endl; 01451 return iBase_FAILURE; 01452 } 01453 verts[x][y] = conn[i]; 01454 } 01455 01456 if( local_logical % 2 ) 01457 { 01458 switch( other_logical - local_logical ) 01459 { 01460 case 0: 01461 return iBase_FAILURE; 01462 case 1: // upper right 01463 vtx_handles.resize( 1 ); 01464 vtx_handles[0] = verts[2][0]; 01465 break; 01466 case 2: // right 01467 vtx_handles.resize( 3 ); 01468 std::copy( verts[2], verts[2] + 3, vtx_handles.begin() ); 01469 break; 01470 case -1: // above 01471 vtx_handles.resize( 3 ); 01472 vtx_handles[0] = verts[0][0]; 01473 vtx_handles[1] = verts[1][0]; 01474 vtx_handles[2] = verts[2][0]; 01475 break; 01476 case -2: // left 01477 vtx_handles.resize( 3 ); 01478 std::copy( verts[0], verts[0] + 3, vtx_handles.begin() ); 01479 break; 01480 case -3: // upper left 01481 vtx_handles.resize( 1 ); 01482 vtx_handles[0] = verts[0][0]; 01483 break; 01484 default: 01485 vtx_handles.clear(); 01486 break; 01487 } 01488 } 01489 else 01490 { 01491 switch( other_logical - local_logical ) 01492 { 01493 case 0: 01494 return iBase_FAILURE; 01495 case 1: // below 01496 vtx_handles.resize( 3 ); 01497 vtx_handles[0] = verts[0][2]; 01498 vtx_handles[1] = verts[1][2]; 01499 vtx_handles[2] = verts[2][2]; 01500 break; 01501 case 2: // right 01502 vtx_handles.resize( 3 ); 01503 std::copy( verts[2], verts[2] + 3, vtx_handles.begin() ); 01504 break; 01505 case 3: // lower right 01506 vtx_handles.resize( 1 ); 01507 vtx_handles[0] = verts[2][2]; 01508 break; 01509 case -1: // lower left 01510 vtx_handles.resize( 1 ); 01511 vtx_handles[0] = verts[0][2]; 01512 break; 01513 case -2: // left 01514 vtx_handles.resize( 3 ); 01515 std::copy( verts[0], verts[0] + 3, vtx_handles.begin() ); 01516 break; 01517 default: 01518 vtx_handles.clear(); 01519 break; 01520 } 01521 } 01522 01523 return iBase_SUCCESS; 01524 } 01525 01526 /**\brief Test querying of part boundary entities 01527 * 01528 * Test: 01529 * - iMeshP_getNumPartBdryEnts 01530 * - iMeshP_getPartBdryEnts 01531 */ 01532 int test_get_part_boundary( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 01533 { 01534 int ierr, rank; 01535 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 01536 01537 // get local part handles and part ids, and global part id list 01538 std::vector< iMeshP_PartHandle > local_handles; 01539 std::vector< iMeshP_Part > local_ids; 01540 std::vector< iMeshP_Part > all_parts = map.get_parts(); 01541 std::map< iMeshP_PartHandle, std::vector< iBase_EntityHandle > > part_bdry; 01542 ierr = get_local_parts( imesh, prtn, local_handles, &local_ids );CHKERR; 01543 01544 // for each combination of local part with any other part, 01545 // check for valid function values. 01546 std::vector< std::pair< iMeshP_Part, iMeshP_Part > > num_failed, num_error, list_failed, list_error, error; 01547 for( size_t i = 0; i < local_handles.size(); ++i ) 01548 { 01549 iMeshP_PartHandle local_handle = local_handles[i]; 01550 iMeshP_Part local_id = local_ids[i]; 01551 for( std::vector< iMeshP_Part >::iterator j = all_parts.begin(); j != all_parts.end(); ++j ) 01552 { 01553 iMeshP_Part other_id = *j; 01554 if( other_id == local_id ) continue; 01555 01556 std::pair< iMeshP_Part, iMeshP_Part > part_pair; 01557 part_pair.first = local_id; 01558 part_pair.second = other_id; 01559 01560 // get expected values 01561 std::vector< iBase_EntityHandle > shared_verts; 01562 ierr = interface_verts( imesh, prtn, local_handle, other_id, map, shared_verts ); 01563 if( ierr != iBase_SUCCESS ) 01564 { 01565 error.push_back( part_pair ); 01566 continue; 01567 } 01568 std::sort( shared_verts.begin(), shared_verts.end() ); 01569 01570 // test iMeshP_getNumPartBdryEnts 01571 int count; 01572 iMeshP_getNumPartBdryEnts( imesh, prtn, local_handle, iBase_VERTEX, iMesh_POINT, other_id, &count, &ierr ); 01573 if( iBase_SUCCESS != ierr ) 01574 num_error.push_back( part_pair ); 01575 else if( count != (int)shared_verts.size() ) 01576 num_failed.push_back( part_pair ); 01577 01578 // test iMeshP_getPartBdryEnts 01579 iBase_EntityHandle* ptr = 0; 01580 int junk = 0; 01581 iMeshP_getPartBdryEnts( imesh, prtn, local_handle, iBase_VERTEX, iMesh_POINT, other_id, &ptr, &junk, &count, 01582 &ierr ); 01583 if( iBase_SUCCESS != ierr ) 01584 list_error.push_back( part_pair ); 01585 else 01586 { 01587 std::copy( ptr, ptr + count, std::back_inserter( part_bdry[local_handles[i]] ) ); 01588 std::sort( ptr, ptr + count ); 01589 if( (int)shared_verts.size() != count || !std::equal( shared_verts.begin(), shared_verts.end(), ptr ) ) 01590 list_failed.push_back( part_pair ); 01591 free( ptr ); 01592 } 01593 } 01594 } 01595 01596 if( !error.empty() ) 01597 { 01598 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01599 << " Internal error for " << error.size() << " part pairs." << std::endl; 01600 ierr = iBase_FAILURE; 01601 } 01602 if( !num_error.empty() ) 01603 { 01604 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01605 << " iMeshP_getNumPartBdryEnts return error for " << num_error.size() << " part pairs." << std::endl; 01606 ierr = iBase_FAILURE; 01607 } 01608 if( !list_error.empty() ) 01609 { 01610 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01611 << " iMeshP_getPartBdryEnts return error for " << list_error.size() << " part pairs." << std::endl; 01612 ierr = iBase_FAILURE; 01613 } 01614 if( !num_failed.empty() ) 01615 { 01616 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01617 << " iMeshP_getNumPartBdryEnts return incorrect results for " << num_failed.size() << " part pairs." 01618 << std::endl; 01619 ierr = iBase_FAILURE; 01620 } 01621 if( !list_failed.empty() ) 01622 { 01623 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01624 << " iMeshP_getPartBdryEnts return incorrect results for " << list_failed.size() << " part pairs." 01625 << std::endl; 01626 ierr = iBase_FAILURE; 01627 } 01628 01629 if( iBase_SUCCESS != ierr ) return ierr; 01630 01631 // test with iMeshP_ALL_PARTS 01632 for( size_t i = 0; i < local_handles.size(); ++i ) 01633 { 01634 std::vector< iBase_EntityHandle >& exp_bdry = part_bdry[local_handles[i]]; 01635 std::sort( exp_bdry.begin(), exp_bdry.end() ); 01636 exp_bdry.erase( std::unique( exp_bdry.begin(), exp_bdry.end() ), exp_bdry.end() ); 01637 std::pair< iMeshP_Part, iMeshP_Part > part_pair; 01638 part_pair.first = local_ids[i]; 01639 part_pair.second = iMeshP_ALL_PARTS; 01640 01641 int num = 0; 01642 iMeshP_getNumPartBdryEnts( imesh, prtn, local_handles[i], iBase_VERTEX, iMesh_POINT, iMeshP_ALL_PARTS, &num, 01643 &ierr ); 01644 if( ierr ) 01645 num_error.push_back( part_pair ); 01646 else if( num != (int)exp_bdry.size() ) 01647 num_failed.push_back( part_pair ); 01648 01649 iBase_EntityHandle* bdry = 0; 01650 int junk = num = 0; 01651 iMeshP_getPartBdryEnts( imesh, prtn, local_handles[i], iBase_VERTEX, iMesh_POINT, iMeshP_ALL_PARTS, &bdry, 01652 &junk, &num, &ierr ); 01653 if( ierr ) 01654 list_error.push_back( part_pair ); 01655 else 01656 { 01657 std::sort( bdry, bdry + num ); 01658 if( num != (int)exp_bdry.size() || !std::equal( bdry, bdry + num, exp_bdry.begin() ) ) 01659 list_failed.push_back( part_pair ); 01660 free( bdry ); 01661 } 01662 } 01663 if( !num_error.empty() ) 01664 { 01665 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01666 << " iMeshP_getNumPartBdryEnts return error for " << num_error.size() << " part pairs." << std::endl; 01667 ierr = iBase_FAILURE; 01668 } 01669 if( !list_error.empty() ) 01670 { 01671 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01672 << " iMeshP_getPartBdryEnts return error for " << list_error.size() << " part pairs." << std::endl; 01673 ierr = iBase_FAILURE; 01674 } 01675 if( !num_failed.empty() ) 01676 { 01677 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01678 << " iMeshP_getNumPartBdryEnts return incorrect results for " << num_failed.size() << " part pairs." 01679 << std::endl; 01680 ierr = iBase_FAILURE; 01681 } 01682 if( !list_failed.empty() ) 01683 { 01684 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01685 << " iMeshP_getPartBdryEnts return incorrect results for " << list_failed.size() << " part pairs." 01686 << std::endl; 01687 ierr = iBase_FAILURE; 01688 } 01689 01690 return ierr; 01691 } 01692 01693 /**\brief Test querying of part boundary entities 01694 * 01695 * Test: 01696 * - iMeshP_initPartBdryEntIter 01697 * - iMeshP_initPartBdryEntArrIter 01698 */ 01699 int test_part_boundary_iter( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 01700 { 01701 int ierr, rank, has_data; 01702 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 01703 01704 // get local part handles and part ids, and global part id list 01705 std::vector< iMeshP_PartHandle > local_handles; 01706 std::vector< iMeshP_Part > local_ids; 01707 std::vector< iMeshP_Part > all_parts = map.get_parts(); 01708 ierr = get_local_parts( imesh, prtn, local_handles, &local_ids );CHKERR; 01709 01710 std::vector< std::pair< iMeshP_Part, iMeshP_Part > > single_failed, single_error, single_step_error, array_failed, 01711 array_error, array_step_error; 01712 for( size_t i = 0; i < local_handles.size(); ++i ) 01713 { 01714 iMeshP_PartHandle local_handle = local_handles[i]; 01715 iMeshP_Part local_id = local_ids[i]; 01716 for( std::vector< iMeshP_Part >::iterator j = all_parts.begin(); j != all_parts.end(); ++j ) 01717 { 01718 iMeshP_Part other_id = *j; 01719 if( other_id == local_id ) continue; 01720 01721 std::pair< iMeshP_Part, iMeshP_Part > part_pair; 01722 part_pair.first = local_id; 01723 part_pair.second = other_id; 01724 01725 // get expected values 01726 std::vector< iBase_EntityHandle > shared_verts; 01727 ierr = interface_verts( imesh, prtn, local_handle, other_id, map, shared_verts ); 01728 if( ierr != iBase_SUCCESS || 0 == shared_verts.size() ) continue; 01729 std::sort( shared_verts.begin(), shared_verts.end() ); 01730 01731 // test single entity iterator 01732 iBase_EntityIterator siter; 01733 iMeshP_initPartBdryEntIter( imesh, prtn, local_handle, iBase_VERTEX, iMesh_POINT, other_id, &siter, &ierr ); 01734 if( ierr != iBase_SUCCESS ) 01735 { 01736 single_error.push_back( part_pair ); 01737 } 01738 else 01739 { 01740 std::vector< iBase_EntityHandle > results; 01741 for( ;; ) 01742 { 01743 iBase_EntityHandle handle; 01744 iMesh_getNextEntIter( imesh, siter, &handle, &has_data, &ierr ); 01745 if( ierr != iBase_SUCCESS ) 01746 { 01747 single_step_error.push_back( part_pair ); 01748 break; 01749 } 01750 if( !has_data ) break; 01751 results.push_back( handle ); 01752 } 01753 01754 std::sort( results.begin(), results.end() ); 01755 if( results.size() != shared_verts.size() || 01756 !std::equal( results.begin(), results.end(), shared_verts.begin() ) ) 01757 single_failed.push_back( part_pair ); 01758 } 01759 iMesh_endEntIter( imesh, siter, &ierr ); 01760 01761 // test array iterator 01762 iBase_EntityArrIterator aiter; 01763 iMeshP_initPartBdryEntArrIter( imesh, prtn, local_handle, iBase_VERTEX, iMesh_POINT, shared_verts.size(), 01764 other_id, &aiter, &ierr ); 01765 if( ierr != iBase_SUCCESS ) 01766 { 01767 array_error.push_back( part_pair ); 01768 iMesh_endEntArrIter( imesh, aiter, &ierr ); 01769 continue; 01770 } 01771 iBase_EntityHandle results[5], *ptr = results; 01772 int junk = 5, count; 01773 iMesh_getNextEntArrIter( imesh, aiter, &ptr, &junk, &count, &has_data, &ierr ); 01774 if( ierr != iBase_SUCCESS || !has_data ) 01775 { 01776 array_step_error.push_back( part_pair ); 01777 iMesh_endEntArrIter( imesh, aiter, &ierr ); 01778 continue; 01779 } 01780 iMesh_endEntArrIter( imesh, aiter, &ierr ); 01781 assert( count <= 5 ); 01782 assert( ptr == results ); 01783 std::sort( ptr, ptr + count ); 01784 if( count != (int)shared_verts.size() || !std::equal( shared_verts.begin(), shared_verts.end(), results ) ) 01785 array_failed.push_back( part_pair ); 01786 } 01787 } 01788 01789 if( !single_error.empty() ) 01790 { 01791 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01792 << " iMeshP_initPartBdryEntIter return error for " << single_error.size() << " part pairs." 01793 << std::endl; 01794 ierr = iBase_FAILURE; 01795 } 01796 if( !single_step_error.empty() ) 01797 { 01798 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01799 << " iMesh_getNextEntIter return error for " << single_step_error.size() << " part pairs." 01800 << std::endl; 01801 ierr = iBase_FAILURE; 01802 } 01803 if( !single_failed.empty() ) 01804 { 01805 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01806 << " iMeshP_initPartBdryEntIter iterator iterated over invalid entities for " << single_failed.size() 01807 << " part pairs." << std::endl; 01808 ierr = iBase_FAILURE; 01809 } 01810 01811 if( !array_error.empty() ) 01812 { 01813 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01814 << " iMeshP_initPartBdryEntArrIter return error for " << array_error.size() << " part pairs." 01815 << std::endl; 01816 ierr = iBase_FAILURE; 01817 } 01818 if( !array_step_error.empty() ) 01819 { 01820 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01821 << " iMesh_getNextEntArrIter return error for " << array_step_error.size() << " part pairs." 01822 << std::endl; 01823 ierr = iBase_FAILURE; 01824 } 01825 if( !array_failed.empty() ) 01826 { 01827 std::cerr << "Processor " << rank << ": Error at " __FILE__ ":" << __LINE__ << std::endl 01828 << " iMeshP_initPartBdryEntArrIter iterator iterated over invalid entities for " 01829 << array_failed.size() << " part pairs." << std::endl; 01830 ierr = iBase_FAILURE; 01831 } 01832 01833 return ierr; 01834 } 01835 01836 /**\brief Test adjacent entity query 01837 * 01838 * Test: 01839 * - iMeshP_getAdjEntities 01840 */ 01841 int test_get_adjacencies( iMesh_Instance /* imesh */, iMeshP_PartitionHandle /* prtn */, const PartMap& ) 01842 { 01843 return iBase_SUCCESS; 01844 } 01845 01846 /**\brief Test entity iterators 01847 * 01848 * Test: 01849 * - iMeshP_initEntIter 01850 * - iMeshP_initEntArrIter 01851 */ 01852 int test_entity_iterator( iMesh_Instance /*imesh */, iMeshP_PartitionHandle /*prtn*/, const PartMap& ) 01853 { 01854 return iBase_SUCCESS; 01855 } 01856 01857 /**\brief Test entity owner queries 01858 * 01859 * Test: 01860 * - iMeshP_getEntOwnerPart 01861 * - iMeshP_getEntOwnerPartArr 01862 * - iMeshP_isEntOwner 01863 * - iMeshP_isEntOwnerArr 01864 */ 01865 int test_entity_owner( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& /* map */ ) 01866 { 01867 int ierr, rank, size; 01868 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 01869 MPI_Comm_size( MPI_COMM_WORLD, &size ); 01870 01871 // get local part handles and part ids 01872 std::vector< iMeshP_PartHandle > local_handles; 01873 std::vector< iMeshP_Part > local_ids; 01874 ierr = get_local_parts( imesh, prtn, local_handles, &local_ids ); 01875 PCHECK; 01876 01877 // test iMeshP_getEntOwnerPart for quads in each part 01878 std::vector< iBase_EntityHandle > all_quads; 01879 std::vector< iMeshP_Part > quad_owners; 01880 int invalid_count = 0; 01881 for( size_t i = 0; i < local_handles.size(); ++i ) 01882 { 01883 std::vector< iBase_EntityHandle > quads; 01884 ierr = get_entities( imesh, local_handles[0], iBase_FACE, iMesh_QUADRILATERAL, quads ); 01885 if( ierr ) break; 01886 01887 for( size_t j = 0; j < quads.size(); ++j ) 01888 { 01889 all_quads.push_back( quads[j] ); 01890 quad_owners.push_back( local_ids[i] ); 01891 iMeshP_Part owner; 01892 iMeshP_getEntOwnerPart( imesh, prtn, quads[j], &owner, &ierr ); 01893 if( iBase_SUCCESS != ierr ) break; 01894 01895 if( owner != local_ids[i] ) ++invalid_count; 01896 } 01897 if( iBase_SUCCESS != ierr ) break; 01898 } 01899 PCHECK; 01900 ASSERT( 0 == invalid_count ); 01901 01902 // test iMeshP_getEntOwnerPartArr for quads in each part 01903 invalid_count = 0; 01904 for( size_t i = 0; i < local_handles.size(); ++i ) 01905 { 01906 std::vector< iBase_EntityHandle > quads; 01907 ierr = get_entities( imesh, local_handles[0], iBase_FACE, iMesh_QUADRILATERAL, quads ); 01908 if( ierr ) break; 01909 01910 std::vector< iMeshP_Part > owners( quads.size() ), expected( quads.size(), local_ids[i] ); 01911 int junk = owners.size(), count; 01912 iMeshP_Part* ptr = &owners[0]; 01913 iMeshP_getEntOwnerPartArr( imesh, prtn, &quads[0], quads.size(), &ptr, &junk, &count, &ierr ); 01914 if( ierr ) break; 01915 assert( ptr == &owners[0] ); 01916 assert( junk == (int)owners.size() ); 01917 assert( count == (int)quads.size() ); 01918 if( owners != expected ) ++invalid_count; 01919 } 01920 PCHECK; 01921 ASSERT( 0 == invalid_count ); 01922 01923 // get all vertices 01924 iBase_EntityHandle* vtx_arr = 0; 01925 int junk1 = 0, num_vtx; 01926 int *junk2 = 0, junk3 = 0, junk4; 01927 iMesh_getEntArrAdj( imesh, &all_quads[0], all_quads.size(), iBase_VERTEX, &vtx_arr, &junk1, &num_vtx, &junk2, 01928 &junk3, &junk4, &ierr ); 01929 PCHECK; 01930 free( junk2 ); 01931 std::sort( vtx_arr, vtx_arr + num_vtx ); 01932 num_vtx = std::unique( vtx_arr, vtx_arr + num_vtx ) - vtx_arr; 01933 std::vector< iBase_EntityHandle > all_verts( vtx_arr, vtx_arr + num_vtx ); 01934 free( vtx_arr ); 01935 01936 // check consistency between iMeshP_getEntOwnerPart and iMeshP_getEntOwnerPartArr 01937 // for all vertices 01938 std::vector< iMeshP_Part > vert_owners( all_verts.size() ); 01939 junk1 = vert_owners.size(); 01940 iMeshP_Part* junk5 = &vert_owners[0]; 01941 iMeshP_getEntOwnerPartArr( imesh, prtn, &all_verts[0], all_verts.size(), &junk5, &junk1, &junk3, &ierr ); 01942 PCHECK; 01943 assert( junk5 == &vert_owners[0] ); 01944 assert( junk1 == (int)vert_owners.size() ); 01945 assert( junk3 == (int)all_verts.size() ); 01946 01947 invalid_count = 0; 01948 for( size_t i = 0; i < all_verts.size(); ++i ) 01949 { 01950 iMeshP_Part owner; 01951 iMeshP_getEntOwnerPart( imesh, prtn, all_verts[i], &owner, &ierr ); 01952 if( iBase_SUCCESS != ierr || owner != vert_owners[i] ) ++invalid_count; 01953 } 01954 ASSERT( 0 == invalid_count ); 01955 01956 // get lists for all entities 01957 std::vector< iBase_EntityHandle > all_entities( all_verts ); 01958 std::copy( all_quads.begin(), all_quads.end(), std::back_inserter( all_entities ) ); 01959 std::vector< iMeshP_Part > all_owners( vert_owners ); 01960 std::copy( quad_owners.begin(), quad_owners.end(), std::back_inserter( all_owners ) ); 01961 01962 // check consistency of iMeshP_isEntOwner for all entities 01963 invalid_count = 0; 01964 ierr = iBase_SUCCESS; 01965 for( size_t i = 0; i < local_handles.size(); ++i ) 01966 { 01967 for( size_t j = 0; ierr == iBase_SUCCESS && j < all_entities.size(); ++j ) 01968 { 01969 int is_owner; 01970 iMeshP_isEntOwner( imesh, prtn, local_handles[i], all_entities[j], &is_owner, &ierr ); 01971 if( ierr != iBase_SUCCESS ) break; 01972 if( !is_owner == ( local_ids[i] == all_owners[j] ) ) ++invalid_count; 01973 } 01974 } 01975 PCHECK; 01976 ASSERT( 0 == invalid_count ); 01977 01978 // check consistency of iMeshP_isEntOwnerArr for all entities 01979 for( size_t i = 0; i < local_handles.size(); ++i ) 01980 { 01981 std::vector< int > is_owner_list( all_entities.size() ); 01982 junk1 = is_owner_list.size(); 01983 int* junk6 = &is_owner_list[0]; 01984 iMeshP_isEntOwnerArr( imesh, prtn, local_handles[i], &all_entities[0], all_entities.size(), &junk6, &junk1, 01985 &junk3, &ierr ); 01986 if( iBase_SUCCESS != ierr ) break; 01987 assert( junk6 == &is_owner_list[0] ); 01988 assert( junk1 == (int)is_owner_list.size() ); 01989 assert( junk3 == (int)all_entities.size() ); 01990 invalid_count = 0; 01991 for( size_t j = 0; j < all_entities.size(); ++j ) 01992 { 01993 if( !( is_owner_list[j] ) == ( local_ids[0] == all_owners[j] ) ) ++invalid_count; 01994 } 01995 } 01996 PCHECK; 01997 ASSERT( 0 == invalid_count ); 01998 01999 // check globally consistent owners for all vertices 02000 02001 // first communicate total number of vertex entries to be sent to root proc 02002 int local_count = all_verts.size(), global_count = 0; 02003 ierr = MPI_Reduce( &local_count, &global_count, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD );CHKERR; 02004 02005 // for each vertex, store { (x << 2) | y, owning part id } 02006 std::vector< int > vtxdata( 2 * all_verts.size() ); 02007 std::vector< double > coords( 3 * all_verts.size() ); 02008 ierr = get_coords( imesh, &all_verts[0], all_verts.size(), &coords[0] );CHKERR; 02009 for( size_t i = 0; i < all_verts.size(); ++i ) 02010 { 02011 int x = (int)round( coords[3 * i] ); 02012 int y = (int)round( coords[3 * i + 1] ); 02013 vtxdata[2 * i] = ( x << 3 ) | y; 02014 vtxdata[2 * i + 1] = vert_owners[i]; 02015 } 02016 02017 // collect all data on root procesor 02018 std::vector< int > all_data( 2 * global_count ); 02019 std::vector< int > displ( size ), counts( size ); 02020 for( int i = 0; i < size; i++ ) 02021 { 02022 counts[i] = vtxdata.size(); 02023 displ[i] = i * vtxdata.size(); 02024 } 02025 02026 // we could have used a simple gather, because all sequences are the same 02027 ierr = MPI_Gatherv( &vtxdata[0], vtxdata.size(), MPI_INT, &all_data[0], &counts[0], &displ[0], MPI_INT, 0, 02028 MPI_COMM_WORLD );CHKERR; 02029 02030 if( rank == 0 ) 02031 { 02032 // map from vertex tag to indices into data 02033 std::multimap< int, int > data_map; 02034 for( int i = 0; i < global_count; ++i ) 02035 { 02036 std::pair< int, int > p; 02037 p.first = all_data[2 * i]; 02038 p.second = i; 02039 data_map.insert( p ); 02040 } 02041 02042 // check consistent data for each vtx 02043 std::multimap< int, int >::const_iterator a, b; 02044 for( a = data_map.begin(); a != data_map.end(); a = b ) 02045 { 02046 for( b = a; b != data_map.end() && a->first == b->first; ++b ) 02047 { 02048 int idx1 = a->second; 02049 int idx2 = b->second; 02050 if( all_data[2 * idx1 + 1] == all_data[2 * idx2 + 1] ) continue; 02051 02052 ierr = iBase_FAILURE; 02053 02054 int proc1 = std::lower_bound( displ.begin(), displ.end(), 2 * idx1 ) - displ.begin(); 02055 if( displ[proc1] != 2 * idx1 ) ++proc1; 02056 int proc2 = std::lower_bound( displ.begin(), displ.end(), 2 * idx2 ) - displ.begin(); 02057 if( displ[proc2] != 2 * idx2 ) ++proc2; 02058 02059 std::cerr << "Error at " __FILE__ ":" << __LINE__ << " : " << std::endl 02060 << " For vertex at (" << ( a->first >> 2 ) << ", " << ( a->first & 3 ) << ") :" << std::endl 02061 << " Processor " << proc1 << " has " << all_data[2 * idx1 + 1] << " as the owning part" 02062 << std::endl 02063 << " Processor " << proc2 << " has " << all_data[2 * idx2 + 1] << " as the owning part" 02064 << std::endl; 02065 } 02066 } 02067 } 02068 02069 return ierr; 02070 } 02071 02072 static int get_part_boundary_verts( iMesh_Instance imesh, 02073 iMeshP_PartitionHandle prtn, 02074 const PartMap& map, 02075 iMeshP_PartHandle part, 02076 std::vector< iBase_EntityHandle >& boundary ) 02077 { 02078 int ierr, logical_id; 02079 ierr = map.part_from_coords( imesh, part, logical_id );CHKERR; 02080 02081 int neighbors[5], num_neighbors; 02082 get_part_neighbors( logical_id, map.get_parts().size(), neighbors, num_neighbors ); 02083 02084 for( int j = 0; j < num_neighbors; ++j ) 02085 { 02086 std::vector< iBase_EntityHandle > iface; 02087 ierr = interface_verts( imesh, prtn, part, neighbors[j], map, iface );CHKERR; 02088 std::copy( iface.begin(), iface.end(), std::back_inserter( boundary ) ); 02089 } 02090 02091 std::sort( boundary.begin(), boundary.end() ); 02092 boundary.erase( std::unique( boundary.begin(), boundary.end() ), boundary.end() ); 02093 return iBase_SUCCESS; 02094 } 02095 02096 /**\brief Test entity status 02097 * 02098 * Test: 02099 * - iMeshP_getEntStatus 02100 * - iMeshP_getEntStatusArr 02101 */ 02102 int test_entity_status( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 02103 { 02104 int ierr, rank, size; 02105 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 02106 MPI_Comm_size( MPI_COMM_WORLD, &size ); 02107 02108 // get local part handles 02109 std::vector< iMeshP_PartHandle > parts; 02110 ierr = get_local_parts( imesh, prtn, parts ); 02111 PCHECK; 02112 02113 // for each part 02114 int num_quad_ent_incorrect = 0, num_quad_ent_error = 0; 02115 int num_quad_arr_incorrect = 0, num_quad_arr_error = 0; 02116 int num_vert_ent_incorrect = 0, num_vert_ent_error = 0; 02117 int num_vert_arr_incorrect = 0, num_vert_arr_error = 0; 02118 for( size_t i = 0; i < parts.size(); ++i ) 02119 { 02120 const iMeshP_PartHandle part = parts[i]; 02121 02122 // get quads and vertices 02123 std::vector< iBase_EntityHandle > quads, verts; 02124 ierr = get_part_quads_and_verts( imesh, part, quads, verts ); 02125 if( ierr ) break; 02126 02127 // check quad status (no ghosting yet) 02128 for( size_t j = 0; j < quads.size(); ++j ) 02129 { 02130 int status; 02131 iMeshP_getEntStatus( imesh, prtn, part, quads[j], &status, &ierr ); 02132 if( ierr != iBase_SUCCESS ) 02133 { 02134 ++num_quad_ent_error; 02135 ierr = iBase_SUCCESS; 02136 continue; 02137 } 02138 02139 if( status != iMeshP_INTERNAL ) ++num_quad_ent_incorrect; 02140 } 02141 02142 // check quad status using iMeshP_getEntStatusArr 02143 std::vector< int > stat_list( quads.size() ); 02144 int* junk1 = &stat_list[0]; 02145 int junk2 = stat_list.size(), count; 02146 iMeshP_getEntStatusArr( imesh, prtn, part, &quads[0], quads.size(), &junk1, &junk2, &count, &ierr ); 02147 if( ierr != iBase_SUCCESS ) 02148 { 02149 ++num_quad_arr_error; 02150 ierr = iBase_SUCCESS; 02151 continue; 02152 } 02153 assert( junk1 == &stat_list[0] ); 02154 assert( junk2 == (int)stat_list.size() ); 02155 assert( count == (int)quads.size() ); 02156 for( size_t j = 0; j < quads.size(); ++j ) 02157 if( stat_list[j] != iMeshP_INTERNAL ) ++num_quad_arr_incorrect; 02158 02159 // figure out which vertices are on the boundary 02160 std::vector< iBase_EntityHandle > boundary; 02161 ierr = get_part_boundary_verts( imesh, prtn, map, part, boundary ); 02162 if( ierr ) break; 02163 std::sort( boundary.begin(), boundary.end() ); 02164 02165 // check vertex status (no ghosting yet) 02166 for( size_t j = 0; j < verts.size(); ++j ) 02167 { 02168 int status; 02169 iMeshP_getEntStatus( imesh, prtn, part, verts[j], &status, &ierr ); 02170 if( ierr != iBase_SUCCESS ) 02171 { 02172 ++num_vert_ent_error; 02173 ierr = iBase_SUCCESS; 02174 continue; 02175 } 02176 bool on_boundary = std::binary_search( boundary.begin(), boundary.end(), verts[j] ); 02177 if( status != ( on_boundary ? iMeshP_BOUNDARY : iMeshP_INTERNAL ) ) ++num_vert_ent_incorrect; 02178 } 02179 02180 // check vert status using iMeshP_getEntStatusArr 02181 stat_list.resize( verts.size() ); 02182 junk1 = &stat_list[0]; 02183 junk2 = stat_list.size(); 02184 iMeshP_getEntStatusArr( imesh, prtn, part, &verts[0], verts.size(), &junk1, &junk2, &count, &ierr ); 02185 if( ierr != iBase_SUCCESS ) 02186 { 02187 ++num_vert_arr_error; 02188 ierr = iBase_SUCCESS; 02189 continue; 02190 } 02191 assert( junk1 == &stat_list[0] ); 02192 assert( junk2 == (int)stat_list.size() ); 02193 assert( count == (int)verts.size() ); 02194 for( size_t j = 0; j < verts.size(); ++j ) 02195 { 02196 bool on_boundary = std::binary_search( boundary.begin(), boundary.end(), verts[j] ); 02197 if( stat_list[j] != ( on_boundary ? iMeshP_BOUNDARY : iMeshP_INTERNAL ) ) ++num_vert_arr_incorrect; 02198 } 02199 } 02200 PCHECK; // check if loop interrupted by any internal errors 02201 02202 ASSERT( 0 == num_quad_ent_error ); 02203 ASSERT( 0 == num_quad_arr_error ); 02204 ASSERT( 0 == num_vert_ent_error ); 02205 ASSERT( 0 == num_vert_arr_error ); 02206 ASSERT( 0 == num_quad_ent_incorrect ); 02207 ASSERT( 0 == num_quad_arr_incorrect ); 02208 ASSERT( 0 == num_vert_ent_incorrect ); 02209 ASSERT( 0 == num_vert_arr_incorrect ); 02210 02211 return iBase_SUCCESS; 02212 } 02213 02214 /**\brief Test information about entity copies for interface entities 02215 * 02216 * Test: 02217 * - iMeshP_getNumCopies 02218 * - iMeshP_getCopyParts 02219 */ 02220 int test_entity_copy_parts( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 02221 { 02222 int ierr, rank, size; 02223 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 02224 MPI_Comm_size( MPI_COMM_WORLD, &size ); 02225 02226 // get local part handles 02227 std::vector< iMeshP_PartHandle > parts; 02228 ierr = get_local_parts( imesh, prtn, parts ); 02229 PCHECK; 02230 ASSERT( !parts.empty() ); 02231 02232 // select a singe part to test 02233 const iMeshP_PartHandle part = parts[0]; 02234 int logical_id; 02235 ierr = map.part_from_coords( imesh, part, logical_id );CHKERR; 02236 const iMeshP_Part part_id = map.part_id_from_local_id( logical_id ); 02237 02238 // get vertices in part 02239 std::vector< iBase_EntityHandle > quads, verts; 02240 ierr = get_part_quads_and_verts( imesh, part, quads, verts ); 02241 PCHECK; 02242 02243 // get neighbors 02244 int neighbors[5], num_neighbors; 02245 get_part_neighbors( logical_id, map.get_parts().size(), neighbors, num_neighbors ); 02246 02247 // build map of sharing data for each vertex 02248 std::map< iBase_EntityHandle, std::vector< iMeshP_Part > > vert_sharing; 02249 for( int j = 0; j < num_neighbors; ++j ) 02250 { 02251 std::vector< iBase_EntityHandle > iface; 02252 ierr = interface_verts( imesh, prtn, part, neighbors[j], map, iface );CHKERR; 02253 for( size_t k = 0; k < iface.size(); ++k ) 02254 vert_sharing[iface[k]].push_back( map.part_id_from_local_id( neighbors[j] ) ); 02255 } 02256 02257 // test getNumCopies for each vertex 02258 std::map< iBase_EntityHandle, std::vector< iMeshP_Part > >::iterator i; 02259 int num_failed = 0, num_incorrect = 0; 02260 for( i = vert_sharing.begin(); i != vert_sharing.end(); ++i ) 02261 { 02262 int count; 02263 iBase_EntityHandle vtx = i->first; 02264 iMeshP_getNumCopies( imesh, prtn, vtx, &count, &ierr ); 02265 if( ierr ) 02266 ++num_failed; 02267 else if( (unsigned)count != i->second.size() + 1 ) // add one for the part we queried from 02268 ++num_incorrect; 02269 } 02270 ASSERT( 0 == num_failed ); 02271 ASSERT( 0 == num_incorrect ); 02272 02273 // get getCopyParts for each vertex 02274 num_failed = num_incorrect = 0; 02275 for( i = vert_sharing.begin(); i != vert_sharing.end(); ++i ) 02276 { 02277 iMeshP_Part* list = 0; 02278 int junk = 0, count; 02279 iMeshP_getCopyParts( imesh, prtn, i->first, &list, &junk, &count, &ierr ); 02280 if( iBase_SUCCESS != ierr ) 02281 { 02282 ++num_failed; 02283 continue; 02284 } 02285 if( (unsigned)count != i->second.size() + 1 ) 02286 { // add one for the part we queried from 02287 ++num_incorrect; 02288 free( list ); 02289 continue; 02290 } 02291 02292 std::vector< iMeshP_Part > expected( i->second ); 02293 expected.push_back( part_id ); 02294 std::sort( list, list + count ); 02295 std::sort( expected.begin(), expected.end() ); 02296 bool eq = std::equal( list, list + count, expected.begin() ); 02297 free( list ); 02298 if( !eq ) ++num_incorrect; 02299 } 02300 ASSERT( 0 == num_failed ); 02301 ASSERT( 0 == num_incorrect ); 02302 02303 return iBase_SUCCESS; 02304 } 02305 02306 // store remote handle data for a vertex 02307 struct VtxCopyData 02308 { 02309 std::vector< iMeshP_Part > parts; 02310 std::vector< iBase_EntityHandle > handles; 02311 }; 02312 02313 /**\brief Test information about entity copies for interface entities 02314 * 02315 * Test: 02316 * - iMeshP_getCopies 02317 * - iMeshP_getCopyOnPart 02318 * - iMeshP_getOwnerCopy 02319 */ 02320 int test_entity_copies( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& /* map */ ) 02321 { 02322 int ierr, rank, size; 02323 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 02324 MPI_Comm_size( MPI_COMM_WORLD, &size ); 02325 02326 // generate a unique ID for each vertex using the coordinates. 02327 // see create_mesh(..): each vertex has integer coordinates (x,y,0) 02328 // with x in [0,inf] and y in [0,4] 02329 // then to an Allgatherv to exchange handles for each processor 02330 02331 // cast everything to iBase_EntityHandle so we can pack it all in one communication 02332 MPI_Datatype tmp_type; 02333 if( sizeof( iBase_EntityHandle ) == sizeof( unsigned ) ) 02334 tmp_type = MPI_UNSIGNED; 02335 else if( sizeof( iBase_EntityHandle ) == sizeof( unsigned long ) ) 02336 tmp_type = MPI_UNSIGNED_LONG; 02337 else if( sizeof( iBase_EntityHandle ) == sizeof( unsigned long long ) ) 02338 tmp_type = MPI_UNSIGNED_LONG_LONG; 02339 else 02340 return iBase_FAILURE; 02341 const MPI_Datatype type = tmp_type; // make it const 02342 02343 // get local part handles 02344 std::vector< iMeshP_PartHandle > parts; 02345 ierr = get_local_parts( imesh, prtn, parts ); 02346 PCHECK; 02347 std::vector< iMeshP_Part > part_ids( parts.size() ); 02348 iMeshP_Part* junk1 = &part_ids[0]; 02349 int junk2 = part_ids.size(), junk3; 02350 iMeshP_getPartIdsFromPartHandlesArr( imesh, prtn, &parts[0], parts.size(), &junk1, &junk2, &junk3, &ierr ); 02351 PCHECK; 02352 assert( junk1 == &part_ids[0] ); 02353 assert( junk2 == (int)part_ids.size() ); 02354 assert( junk3 == (int)parts.size() ); 02355 02356 // build list of {vtx_id, part_id, handle} tuples to send 02357 // also build list of local vertex handles 02358 std::vector< iBase_EntityHandle > local_data, local_vertices; 02359 for( size_t i = 0; i < parts.size(); ++i ) 02360 { 02361 // get vertices 02362 std::vector< iBase_EntityHandle > quads, verts; 02363 ierr = get_part_quads_and_verts( imesh, parts[i], quads, verts ); 02364 if( ierr ) break; 02365 02366 // add all vertices to local_data 02367 for( size_t j = 0; j < verts.size(); ++j ) 02368 { 02369 int tag = 0; 02370 ierr = vertex_tag( imesh, verts[j], tag ); 02371 if( ierr ) break; 02372 long tmp_h = tag; 02373 local_data.push_back( (iBase_EntityHandle)tmp_h ); 02374 tmp_h = part_ids[i]; 02375 local_data.push_back( (iBase_EntityHandle)tmp_h ); 02376 local_data.push_back( verts[j] ); 02377 } 02378 if( ierr ) break; 02379 02380 std::copy( verts.begin(), verts.end(), std::back_inserter( local_vertices ) ); 02381 } 02382 02383 // build list of local vertices 02384 std::sort( local_vertices.begin(), local_vertices.end() ); 02385 local_vertices.erase( std::unique( local_vertices.begin(), local_vertices.end() ), local_vertices.end() ); 02386 std::vector< int > local_vtx_tags( local_vertices.size() );CHKERR; 02387 for( size_t i = 0; i < local_vertices.size(); ++i ) 02388 { 02389 ierr = vertex_tag( imesh, local_vertices[i], local_vtx_tags[i] ); 02390 if( ierr ) break; 02391 } 02392 CHKERR; 02393 02394 // communicate data 02395 std::vector< int > gcounts( size ), gdisp( size ); 02396 int local_data_size = local_data.size(); 02397 ierr = MPI_Allgather( &local_data_size, 1, MPI_INT, &gcounts[0], 1, MPI_INT, MPI_COMM_WORLD );CHKERR; 02398 gdisp[0] = 0; 02399 for( int i = 1; i < size; ++i ) 02400 gdisp[i] = gdisp[i - 1] + gcounts[i - 1]; 02401 std::vector< iBase_EntityHandle > global_data( gdisp[size - 1] + gcounts[size - 1] ); 02402 ierr = MPI_Allgatherv( &local_data[0], local_data_size, type, &global_data[0], &gcounts[0], &gdisp[0], type, 02403 MPI_COMM_WORLD );CHKERR; 02404 02405 // arrange global data in a more useful way 02406 std::map< int, VtxCopyData > vtx_sharing; 02407 assert( global_data.size() % 3 == 0 ); 02408 for( size_t i = 0; i < global_data.size(); i += 3 ) 02409 { 02410 int tag = (int)(size_t)global_data[i]; 02411 iMeshP_Part part = (iMeshP_Part)(size_t)global_data[i + 1]; 02412 iBase_EntityHandle handle = global_data[i + 2]; 02413 vtx_sharing[tag].parts.push_back( part ); 02414 vtx_sharing[tag].handles.push_back( handle ); 02415 } 02416 02417 // test iMeshP_getCopies for each local vertex 02418 int num_error = 0, num_incorrect = 0, junk4; 02419 for( size_t i = 0; i < local_vertices.size(); ++i ) 02420 { 02421 int num_copies = -1; 02422 // iMeshP_Part* part_ids = 0; 02423 iMeshP_Part* ptr_part_ids = 0; // Use ptr_part_ids to avoid shadowing std::vector<iMeshP_Part> part_ids 02424 iBase_EntityHandle* copies = 0; 02425 junk2 = junk3 = junk4 = 0; 02426 iMeshP_getCopies( imesh, prtn, local_vertices[i], &ptr_part_ids, &junk2, &num_copies, &copies, &junk3, &junk4, 02427 &ierr ); 02428 if( iBase_SUCCESS != ierr ) 02429 { 02430 ++num_error; 02431 continue; 02432 } 02433 assert( junk4 == num_copies ); 02434 02435 VtxCopyData& expected = vtx_sharing[local_vtx_tags[i]]; 02436 if( num_copies != (int)expected.parts.size() ) 02437 ++num_incorrect; 02438 else 02439 for( size_t j = 0; j < expected.parts.size(); ++j ) 02440 { 02441 int idx = std::find( ptr_part_ids, ptr_part_ids + num_copies, expected.parts[j] ) - ptr_part_ids; 02442 if( idx == num_copies || copies[idx] != expected.handles[j] ) 02443 { 02444 ++num_incorrect; 02445 break; 02446 } 02447 } 02448 free( ptr_part_ids ); 02449 free( copies ); 02450 } 02451 ASSERT( 0 == num_error ); 02452 ASSERT( 0 == num_incorrect ); 02453 02454 // test iMeshP_getCopyOnPart for each local vertex 02455 num_error = num_incorrect = 0; 02456 for( size_t i = 0; i < local_vertices.size(); ++i ) 02457 { 02458 VtxCopyData& expected = vtx_sharing[local_vtx_tags[i]]; 02459 for( size_t j = 0; j < expected.parts.size(); ++j ) 02460 { 02461 iBase_EntityHandle copy; 02462 iMeshP_getCopyOnPart( imesh, prtn, local_vertices[i], expected.parts[j], ©, &ierr ); 02463 if( iBase_SUCCESS != ierr ) 02464 ++num_error; 02465 else if( expected.handles[j] != copy ) 02466 ++num_incorrect; 02467 } 02468 } 02469 ASSERT( 0 == num_error ); 02470 ASSERT( 0 == num_incorrect ); 02471 02472 // test iMeshP_getOwnerCopy for each local vertex 02473 num_error = num_incorrect = 0; 02474 for( size_t i = 0; i < local_vertices.size(); ++i ) 02475 { 02476 VtxCopyData& expected = vtx_sharing[local_vtx_tags[i]]; 02477 iMeshP_Part owner_id = 0; 02478 iMeshP_getEntOwnerPart( imesh, prtn, local_vertices[i], &owner_id, &ierr ); 02479 if( iBase_SUCCESS != ierr ) continue; // not testing getEntOwnerPart here 02480 02481 size_t idx = std::find( expected.parts.begin(), expected.parts.end(), owner_id ) - expected.parts.begin(); 02482 if( idx == expected.parts.size() ) continue; // not testing getEntOwnerPart here 02483 02484 iMeshP_Part owner_id_2 = 0; 02485 iBase_EntityHandle copy = 0; 02486 iMeshP_getOwnerCopy( imesh, prtn, local_vertices[i], &owner_id_2, ©, &ierr ); 02487 if( iBase_SUCCESS != ierr ) 02488 ++num_error; 02489 else if( owner_id_2 != owner_id && copy != expected.handles[idx] ) 02490 ++num_incorrect; 02491 } 02492 ASSERT( 0 == num_error ); 02493 ASSERT( 0 == num_incorrect ); 02494 02495 return iBase_SUCCESS; 02496 } 02497 02498 int get_num_adj_quads( iMesh_Instance imesh, iBase_EntityHandle vtx, int& num ) 02499 { 02500 iBase_EntityHandle* list = 0; 02501 int ierr, junk = 0; 02502 iMesh_getEntAdj( imesh, vtx, iBase_FACE, &list, &junk, &num, &ierr ); 02503 if( iBase_SUCCESS == ierr ) free( list ); 02504 return ierr; 02505 } 02506 02507 int get_adj( iMesh_Instance imesh, iBase_EntityHandle ent, int type, std::vector< iBase_EntityHandle >& adj ) 02508 { 02509 iBase_EntityHandle* list = 0; 02510 int ierr, num, junk = 0; 02511 iMesh_getEntAdj( imesh, ent, type, &list, &junk, &num, &ierr ); 02512 if( iBase_SUCCESS == ierr ) 02513 { 02514 std::copy( list, list + num, std::back_inserter( adj ) ); 02515 free( list ); 02516 } 02517 return ierr; 02518 } 02519 02520 // assume regular quad mesh 02521 int get_boundary_vertices( iMesh_Instance imesh, std::vector< iBase_EntityHandle >& bdry ) 02522 { 02523 int ierr, n; 02524 iBase_EntitySetHandle root; 02525 iMesh_getRootSet( imesh, &root, &ierr );CHKERR; 02526 std::vector< iBase_EntityHandle > all_verts; 02527 ierr = get_entities( imesh, root, iBase_VERTEX, iMesh_POINT, all_verts );CHKERR; 02528 bdry.clear(); 02529 for( size_t i = 0; i < all_verts.size(); ++i ) 02530 { 02531 ierr = get_num_adj_quads( imesh, all_verts[i], n );CHKERR; 02532 if( n != 4 ) bdry.push_back( all_verts[i] ); 02533 } 02534 return iBase_SUCCESS; 02535 } 02536 02537 int check_one_layer( iMesh_Instance imesh, 02538 iBase_EntityHandle vtx, 02539 const std::vector< iBase_EntityHandle >& sorted_vertices ) 02540 { 02541 int ierr; 02542 if( std::binary_search( sorted_vertices.begin(), sorted_vertices.end(), vtx ) ) return iBase_SUCCESS; 02543 std::vector< iBase_EntityHandle > quads, verts; 02544 ierr = get_adj( imesh, vtx, iBase_FACE, quads );CHKERR; 02545 for( size_t i = 0; i < quads.size(); ++i ) 02546 { 02547 verts.clear(); 02548 ierr = get_adj( imesh, quads[i], iBase_VERTEX, verts );CHKERR; 02549 for( size_t j = 0; j < verts.size(); ++j ) 02550 { 02551 if( std::binary_search( sorted_vertices.begin(), sorted_vertices.end(), verts[j] ) ) return iBase_SUCCESS; 02552 } 02553 } 02554 02555 return iBase_FAILURE; 02556 } 02557 02558 // get number of adjacent quads to each vertex, both on the local 02559 // processor and in the entire mesh 02560 int get_num_adj_all( iMesh_Instance imesh, 02561 const std::vector< iBase_EntityHandle >& verts, 02562 std::vector< int >& num_local_adj, 02563 std::vector< int >& num_all_adj ) 02564 { 02565 int ierr, size; 02566 MPI_Comm_size( MPI_COMM_WORLD, &size ); 02567 02568 std::vector< int > vtx_tags( verts.size() ); 02569 num_local_adj.resize( verts.size() ); 02570 for( size_t i = 0; i < verts.size(); ++i ) 02571 { 02572 ierr = get_num_adj_quads( imesh, verts[i], num_local_adj[i] );CHKERR; 02573 ierr = vertex_tag( imesh, verts[i], vtx_tags[i] );CHKERR; 02574 } 02575 02576 std::vector< int > counts( size ), displ( size ); 02577 int num_vtx = verts.size(); 02578 ierr = MPI_Allgather( &num_vtx, 1, MPI_INT, &counts[0], 1, MPI_INT, MPI_COMM_WORLD );CHKERR; 02579 displ[0] = 0; 02580 for( int i = 1; i < size; ++i ) 02581 displ[i] = displ[i - 1] + counts[i - 1]; 02582 int total = displ[size - 1] + counts[size - 1]; 02583 std::vector< int > all_tags( total ), all_adj_counts( total ); 02584 ierr = MPI_Allgatherv( &vtx_tags[0], vtx_tags.size(), MPI_INT, &all_tags[0], &counts[0], &displ[0], MPI_INT, 02585 MPI_COMM_WORLD );CHKERR; 02586 ierr = MPI_Allgatherv( &num_local_adj[0], num_local_adj.size(), MPI_INT, &all_adj_counts[0], &counts[0], &displ[0], 02587 MPI_INT, MPI_COMM_WORLD );CHKERR; 02588 02589 num_all_adj.clear(); 02590 num_all_adj.resize( total, 0 ); 02591 for( int i = 0; i < total; ++i ) 02592 { 02593 std::vector< int >::iterator it = std::find( vtx_tags.begin(), vtx_tags.end(), all_tags[i] ); 02594 if( it == vtx_tags.end() ) continue; 02595 int idx = it - vtx_tags.begin(); 02596 num_all_adj[idx] += all_adj_counts[i]; 02597 } 02598 02599 return iBase_SUCCESS; 02600 } 02601 02602 /**\brief Test creation of ghost entities 02603 * 02604 * Test: 02605 * - iMeshP_createGhostEntsAll 02606 */ 02607 int test_create_ghost_ents( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& /* map */ ) 02608 { 02609 int ierr; 02610 02611 // get boundary vertices 02612 std::vector< iBase_EntityHandle > bdry; 02613 ierr = get_boundary_vertices( imesh, bdry ); 02614 PCHECK; 02615 // get counts of adjacent entities 02616 std::vector< int > num_local_adj, num_global_adj; 02617 ierr = get_num_adj_all( imesh, bdry, num_local_adj, num_global_adj ); 02618 PCHECK; 02619 // create one layer of ghost entities 02620 iMeshP_createGhostEntsAll( imesh, prtn, iBase_FACE, iBase_VERTEX, 1, 0, &ierr ); 02621 PCHECK; 02622 // check that each vertex has the correct number of adjacent entities 02623 int num_incorrect = 0; 02624 for( size_t i = 0; i < bdry.size(); ++i ) 02625 { 02626 int n; 02627 ierr = get_num_adj_quads( imesh, bdry[i], n ); 02628 if( iBase_SUCCESS != ierr || num_global_adj[i] != n ) ++num_incorrect; 02629 } 02630 ASSERT( 0 == num_incorrect ); 02631 // get new the new boundary 02632 std::vector< iBase_EntityHandle > new_bdry; 02633 ierr = get_boundary_vertices( imesh, new_bdry ); 02634 PCHECK; 02635 // check that each vertex on the new boundary is separated by 02636 // at most one layer from the old boundary 02637 std::sort( bdry.begin(), bdry.end() ); 02638 num_incorrect = 0; 02639 for( size_t i = 0; i < new_bdry.size(); ++i ) 02640 { 02641 ierr = check_one_layer( imesh, new_bdry[i], bdry ); 02642 if( ierr ) ++num_incorrect; 02643 } 02644 ASSERT( 0 == num_incorrect ); 02645 // make another layer of ghost entiites 02646 bdry.swap( new_bdry ); 02647 new_bdry.clear(); 02648 ierr = get_num_adj_all( imesh, bdry, num_local_adj, num_global_adj ); 02649 PCHECK; 02650 iMeshP_createGhostEntsAll( imesh, prtn, iBase_FACE, iBase_VERTEX, 2, 0, &ierr ); 02651 PCHECK; 02652 // check that each vertex has the correct number of adjacent entities 02653 num_incorrect = 0; 02654 for( size_t i = 0; i < bdry.size(); ++i ) 02655 { 02656 int n; 02657 ierr = get_num_adj_quads( imesh, bdry[i], n ); 02658 if( iBase_SUCCESS != ierr || num_global_adj[i] != n ) ++num_incorrect; 02659 } 02660 // check that each vertex on the new boundary is separated by 02661 // at most one layer from the old boundary 02662 std::sort( bdry.begin(), bdry.end() ); 02663 num_incorrect = 0; 02664 for( size_t i = 0; i < new_bdry.size(); ++i ) 02665 { 02666 ierr = check_one_layer( imesh, new_bdry[i], bdry ); 02667 if( ierr ) ++num_incorrect; 02668 } 02669 ASSERT( 0 == num_incorrect ); 02670 02671 return iBase_SUCCESS; 02672 } 02673 02674 /**\brief Test exchange entities 02675 * 02676 * Test: 02677 * - iMeshP_exchEntArrToPartsAll 02678 */ 02679 int test_exchange_ents( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& map ) 02680 { 02681 int ierr, rank, size; 02682 int num_err = 0; 02683 iMeshP_RequestHandle request; 02684 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 02685 MPI_Comm_size( MPI_COMM_WORLD, &size ); 02686 02687 std::vector< iBase_EntityHandle > all_elems; 02688 std::vector< iMeshP_Part > all_ids; 02689 std::vector< iBase_EntityHandle > quads; 02690 02691 // get local part handles and part ids 02692 std::vector< iMeshP_PartHandle > local_handles; 02693 std::vector< iMeshP_Part > local_ids; 02694 ierr = get_local_parts( imesh, prtn, local_handles, &local_ids ); 02695 PCHECK; 02696 02697 // get loacal quads before exchange 02698 quads.clear(); 02699 ierr = get_entities( imesh, local_handles[0], iBase_FACE, iMesh_QUADRILATERAL, quads );CHKERR; 02700 int n_quads = quads.size(); 02701 02702 // send all elements in local processor to all other processors 02703 for( size_t i = 0; i < map.get_parts().size(); ++i ) 02704 { 02705 if( map.get_parts()[i] == (unsigned int)rank ) continue; // skip own rank 02706 02707 for( int j = 0; j < n_quads; j++ ) 02708 { 02709 all_elems.push_back( quads[j] ); 02710 all_ids.push_back( map.get_parts()[i] ); 02711 } 02712 } 02713 02714 // exchange entities 02715 iMeshP_exchEntArrToPartsAll( imesh, prtn, &all_elems[0], all_elems.size(), &all_ids[0], 0, 0, &request, &ierr ); 02716 if( iBase_SUCCESS != ierr ) ++num_err; 02717 02718 // get local quads after exchange 02719 quads.clear(); 02720 ierr = get_entities( imesh, local_handles[0], iBase_FACE, iMesh_QUADRILATERAL, quads );CHKERR; 02721 02722 // # of elements should be # of quads * # of processors 02723 ASSERT( quads.size() == (unsigned int)n_quads * size ); 02724 02725 ASSERT( 0 == num_err ); 02726 02727 return iBase_SUCCESS; 02728 } 02729 02730 /**\brief Test commuinication of tag data 02731 * 02732 * Test: 02733 * - iMeshP_pushTags 02734 * - iMeshP_pushTagsEnt 02735 */ 02736 int test_push_tag_data_common( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, int num_ghost_layers ) 02737 { 02738 const char* src_name = "test_src"; 02739 const char* dst_name = "test_dst"; 02740 int ierr, rank; 02741 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 02742 02743 if( num_ghost_layers ) 02744 { 02745 iMeshP_createGhostEntsAll( imesh, prtn, iBase_FACE, iBase_VERTEX, num_ghost_layers, 0, &ierr ); 02746 PCHECK; 02747 } 02748 02749 iBase_TagHandle src_tag, dst_tag; 02750 iMesh_createTag( imesh, src_name, 1, iBase_INTEGER, &src_tag, &ierr, strlen( src_name ) );CHKERR; 02751 iMesh_createTag( imesh, dst_name, 1, iBase_INTEGER, &dst_tag, &ierr, strlen( dst_name ) );CHKERR; 02752 02753 iBase_EntitySetHandle root; 02754 iMesh_getRootSet( imesh, &root, &ierr );CHKERR; 02755 02756 std::vector< iBase_EntityHandle > verts; 02757 ierr = get_entities( imesh, root, iBase_VERTEX, iMesh_POINT, verts );CHKERR; 02758 02759 // test iMeshP_pushTags 02760 // each processor writes its rank on all vertices 02761 // after push, each vertex should be tagged with the rank of its owner 02762 02763 std::vector< int > tag_vals( verts.size(), rank ); 02764 iMesh_setIntArrData( imesh, &verts[0], verts.size(), src_tag, &tag_vals[0], tag_vals.size(), &ierr );CHKERR; 02765 02766 iMeshP_pushTags( imesh, prtn, src_tag, dst_tag, iBase_VERTEX, iMesh_POINT, &ierr ); 02767 PCHECK; 02768 02769 tag_vals.clear(); 02770 tag_vals.resize( verts.size(), -1 ); 02771 iBase_TagHandle id_tag; 02772 iMesh_getTagHandle( imesh, "GLOBAL_ID", &id_tag, &ierr, strlen( "GLOBAL_ID" ) ); 02773 std::vector< int > ids( verts.size() ); 02774 int *junk1 = &ids[0], junk2 = ids.size(), junk3; 02775 iMesh_getIntArrData( imesh, &verts[0], verts.size(), id_tag, &junk1, &junk2, &junk3, &ierr ); 02776 PCHECK; 02777 int errcount = 0; 02778 for( size_t i = 0; i < verts.size(); ++i ) 02779 { 02780 iMesh_getIntData( imesh, verts[i], dst_tag, &tag_vals[i], &ierr ); 02781 if( ierr != iBase_SUCCESS ) 02782 { 02783 std::cerr << "Rank " << rank << " : getIntData failed for vertex " << ids[i] << std::endl; 02784 std::cerr.flush(); 02785 ++errcount; 02786 } 02787 } 02788 ASSERT( 0 == errcount ); 02789 02790 // int *junk1 = &tag_vals[0], junk2 = tag_vals.size(), junk3; 02791 // iMesh_getIntArrData( imesh, &verts[0], verts.size(), dst_tag, &junk1, &junk2, &junk3, &ierr 02792 // ); PCHECK; assert( junk1 == &tag_vals[0] ); assert( junk2 == (int)tag_vals.size() ); assert( 02793 // junk3 == (int)verts.size() ); 02794 02795 std::vector< int > expected( verts.size() ); 02796 std::vector< iMeshP_Part > parts( verts.size() ); 02797 iMeshP_Part* junk4 = &parts[0]; 02798 junk2 = parts.size(); 02799 iMeshP_getEntOwnerPartArr( imesh, prtn, &verts[0], verts.size(), &junk4, &junk2, &junk3, &ierr ); 02800 PCHECK; 02801 assert( junk4 == &parts[0] ); 02802 assert( junk2 == (int)parts.size() ); 02803 assert( junk3 == (int)verts.size() ); 02804 junk1 = &expected[0]; 02805 junk2 = expected.size(); 02806 iMeshP_getRankOfPartArr( imesh, prtn, &parts[0], parts.size(), &junk1, &junk2, &junk3, &ierr ); 02807 PCHECK; 02808 assert( junk1 == &expected[0] ); 02809 assert( junk2 == (int)expected.size() ); 02810 assert( junk3 == (int)parts.size() ); 02811 02812 ASSERT( tag_vals == expected ); 02813 02814 // test iMeshP_pushTagsEnt 02815 // write -1 on all vertices 02816 // For each vertex owned by this processor and shared with more than 02817 // two others, write the rank of the owning processor. 02818 02819 tag_vals.clear(); 02820 tag_vals.resize( verts.size(), -1 ); 02821 iMesh_setIntArrData( imesh, &verts[0], verts.size(), src_tag, &tag_vals[0], tag_vals.size(), &ierr ); 02822 PCHECK; 02823 tag_vals.resize( verts.size(), -1 ); 02824 iMesh_setIntArrData( imesh, &verts[0], verts.size(), dst_tag, &tag_vals[0], tag_vals.size(), &ierr ); 02825 PCHECK; 02826 02827 std::vector< iBase_EntityHandle > some; 02828 for( size_t i = 0; i < verts.size(); ++i ) 02829 { 02830 int num; 02831 iMeshP_getNumCopies( imesh, prtn, verts[i], &num, &ierr ); 02832 if( iBase_SUCCESS != ierr ) break; 02833 if( num > 2 ) 02834 some.push_back( verts[i] ); 02835 else 02836 expected[i] = -1; 02837 } 02838 02839 tag_vals.clear(); 02840 tag_vals.resize( some.size(), rank ); 02841 iMesh_setIntArrData( imesh, &some[0], some.size(), src_tag, &tag_vals[0], tag_vals.size(), &ierr ); 02842 PCHECK; 02843 02844 iMeshP_pushTagsEnt( imesh, prtn, src_tag, dst_tag, &some[0], some.size(), &ierr ); 02845 PCHECK; 02846 02847 tag_vals.clear(); 02848 tag_vals.resize( verts.size(), -1 ); 02849 junk1 = &tag_vals[0]; 02850 junk2 = tag_vals.size(); 02851 iMesh_getIntArrData( imesh, &verts[0], verts.size(), dst_tag, &junk1, &junk2, &junk3, &ierr );CHKERR; 02852 assert( junk1 == &tag_vals[0] ); 02853 assert( junk2 == (int)tag_vals.size() ); 02854 assert( junk3 == (int)verts.size() ); 02855 02856 ASSERT( tag_vals == expected ); 02857 return iBase_SUCCESS; 02858 } 02859 02860 /**\brief Test commuinication of tag data 02861 * 02862 * Test: 02863 * - iMeshP_pushTags 02864 * - iMeshP_pushTagsEnt 02865 */ 02866 int test_push_tag_data_iface( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& ) 02867 { 02868 return test_push_tag_data_common( imesh, prtn, 0 ); 02869 } 02870 02871 /**\brief Test commuinication of tag data 02872 * 02873 * Test: 02874 * - iMeshP_pushTags 02875 * - iMeshP_pushTagsEnt 02876 */ 02877 int test_push_tag_data_ghost( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, const PartMap& ) 02878 { 02879 return test_push_tag_data_common( imesh, prtn, 1 ); 02880 } 02881 02882 /************************************************************************** 02883 PartMap class 02884 **************************************************************************/ 02885 02886 int PartMap::build_map( iMesh_Instance imesh, iMeshP_PartitionHandle prtn, int num_expected_parts ) 02887 { 02888 int ierr, rank, size; 02889 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 02890 MPI_Comm_size( MPI_COMM_WORLD, &size ); 02891 02892 // get local parts 02893 std::vector< iMeshP_PartHandle > local_parts; 02894 std::vector< iMeshP_Part > imesh_ids; 02895 ierr = get_local_parts( imesh, prtn, local_parts, &imesh_ids );CHKERR; 02896 02897 // get logical ids for local parts 02898 std::vector< int > local_ids( local_parts.size() ); 02899 for( size_t i = 0; i < local_parts.size(); ++i ) 02900 { 02901 ierr = part_from_coords( imesh, local_parts[i], local_ids[i] );CHKERR; 02902 } 02903 02904 // get total number of parts 02905 int num_global = 0, num_local = local_parts.size(); 02906 ierr = MPI_Allreduce( &num_local, &num_global, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD );CHKERR; 02907 if( num_global != num_expected_parts ) 02908 { 02909 std::cerr << "Invalid/unexpected global part count at " __FILE__ ":" << __LINE__ << " (proc " << rank 02910 << "): " << std::endl 02911 << " Expected: " << num_expected_parts << std::endl 02912 << " Actual: " << num_global << std::endl; 02913 return 1; 02914 } 02915 02916 // get counts and displacements for Allgatherv calls 02917 std::vector< int > dspls( size ), counts( size ); 02918 ierr = MPI_Allgather( &num_local, 1, MPI_INT, &counts[0], 1, MPI_INT, MPI_COMM_WORLD );CHKERR; 02919 dspls[0] = 0; 02920 for( int i = 1; i < size; ++i ) 02921 dspls[i] = dspls[i - 1] + counts[i - 1]; 02922 02923 // gather iMeshP_Part list from each processor 02924 std::vector< unsigned > global_part_ids( num_expected_parts ); 02925 assert( sizeof( iMeshP_Part ) == sizeof( int ) ); 02926 ierr = MPI_Allgatherv( &imesh_ids[0], num_local, MPI_UNSIGNED, &global_part_ids[0], &counts[0], &dspls[0], 02927 MPI_UNSIGNED, MPI_COMM_WORLD );CHKERR; 02928 02929 // gather local ids from each processor 02930 std::vector< int > global_id_list( num_expected_parts ); 02931 ierr = MPI_Allgatherv( &local_ids[0], num_local, MPI_INT, &global_id_list[0], &counts[0], &dspls[0], MPI_INT, 02932 MPI_COMM_WORLD );CHKERR; 02933 02934 // build owner list 02935 std::vector< int > global_owners( num_expected_parts ); 02936 for( int i = 0; i < size; ++i ) 02937 for( int j = 0; j < counts[i]; ++j ) 02938 global_owners[dspls[i] + j] = i; 02939 02940 // populate member lists 02941 sortedPartList = global_part_ids; 02942 std::sort( sortedPartList.begin(), sortedPartList.end() ); 02943 partLocalIds.resize( num_expected_parts ); 02944 partRanks.resize( num_expected_parts ); 02945 for( int i = 0; i < num_expected_parts; ++i ) 02946 { 02947 int idx = std::lower_bound( sortedPartList.begin(), sortedPartList.end(), global_part_ids[i] ) - 02948 sortedPartList.begin(); 02949 partLocalIds[idx] = global_id_list[i]; 02950 partRanks[idx] = global_owners[i]; 02951 } 02952 02953 // do some consistency checking 02954 if( std::unique( sortedPartList.begin(), sortedPartList.end() ) != sortedPartList.end() ) 02955 { 02956 if( rank == 0 ) 02957 { 02958 std::cerr << "ERROR: Duplicate iMeshP_Part values detected at " __FILE__ ":" << __LINE__ << std::endl; 02959 } 02960 return 1; 02961 } 02962 02963 // build revesre local id map and check for duplicates 02964 localIdReverseMap.clear(); 02965 localIdReverseMap.resize( num_expected_parts, -1 ); 02966 for( int i = 0; i < num_expected_parts; ++i ) 02967 { 02968 int idx = partLocalIds[i]; 02969 if( localIdReverseMap[idx] != -1 ) 02970 { 02971 if( rank == 0 ) 02972 { 02973 std::cerr << "ERROR: Part mesh has been duplicated in multiple parts." << std::endl 02974 << " Detected at " __FILE__ ":" << __LINE__ << std::endl 02975 << " See PartMap::part_from_coords" << std::endl; 02976 } 02977 return 1; 02978 } 02979 if( idx >= num_expected_parts ) 02980 { 02981 if( rank == 0 ) 02982 { 02983 std::cerr << "ERROR: Part mesh invalid/incorrect mesh." << std::endl 02984 << " Detected at " __FILE__ ":" << __LINE__ << std::endl 02985 << " See PartMap::part_from_coords" << std::endl; 02986 } 02987 return 1; 02988 } 02989 02990 localIdReverseMap[idx] = i; 02991 } 02992 02993 return 0; 02994 } 02995 02996 void PartMap::part_id_from_rank( int rank, std::vector< iMeshP_Part >& parts ) const 02997 { 02998 for( size_t i = 0; i < sortedPartList.size(); ++i ) 02999 if( partRanks[i] == rank ) parts.push_back( sortedPartList[i] ); 03000 } 03001 03002 void PartMap::local_id_from_rank( int rank, std::vector< int >& ids ) const 03003 { 03004 for( size_t i = 0; i < sortedPartList.size(); ++i ) 03005 if( partRanks[i] == rank ) ids.push_back( partLocalIds[i] ); 03006 } 03007 03008 int PartMap::part_from_coords( iMesh_Instance imesh, iMeshP_PartHandle part, int& id ) 03009 { 03010 int ierr, rank; 03011 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 03012 03013 // get elements 03014 const int num_elem = 4; 03015 iBase_EntityHandle array[num_elem]; 03016 iBase_EntityHandle* ptr = array; 03017 int junk1 = num_elem, n = -1; 03018 iMesh_getEntities( imesh, part, iBase_FACE, iMesh_QUADRILATERAL, &ptr, &junk1, &n, &ierr );CHKERR; 03019 assert( ptr == array ); 03020 assert( junk1 == num_elem ); 03021 if( n != num_elem ) 03022 { 03023 std::cerr << "Internal error at " __FILE__ ":" << __LINE__ << " (proc " << rank 03024 << "): Expected all parts to have " << num_elem << " elements. Found one with " << n << std::endl; 03025 return 1; 03026 } 03027 03028 // get vertices 03029 iBase_EntityHandle adj_array[4 * num_elem]; 03030 int junk2, junk3, offset_array[5]; 03031 ptr = adj_array; 03032 junk1 = sizeof( adj_array ) / sizeof( adj_array[0] ); 03033 junk2 = sizeof( offset_array ) / sizeof( offset_array[0] ); 03034 int* ptr2 = offset_array; 03035 iMesh_getEntArrAdj( imesh, array, num_elem, iBase_VERTEX, &ptr, &junk1, &n, &ptr2, &junk2, &junk3, &ierr );CHKERR; 03036 assert( ptr == adj_array ); 03037 assert( ptr2 == offset_array ); 03038 assert( junk1 == sizeof( adj_array ) / sizeof( adj_array[0] ) ); 03039 assert( junk2 == sizeof( offset_array ) / sizeof( offset_array[0] ) ); 03040 assert( n == 4 * num_elem ); 03041 assert( offset_array[0] == 0 ); 03042 for( int i = 1; i < junk3; ++i ) 03043 assert( offset_array[i] - offset_array[i - 1] == 4 ); 03044 03045 // find center vertex 03046 iBase_EntityHandle vtx; 03047 bool all_match; 03048 for( int i = 0; i < 4; ++i ) 03049 { 03050 vtx = adj_array[i]; 03051 all_match = true; 03052 for( int j = 1; j < 4; ++j ) 03053 { 03054 iBase_EntityHandle* mvtx = adj_array + 4 * j; 03055 int k; 03056 for( k = 0; k < 4; ++k ) 03057 if( mvtx[k] == vtx ) break; 03058 if( k == 4 ) all_match = false; 03059 } 03060 if( all_match ) break; 03061 } 03062 assert( all_match ); 03063 03064 // get center vertex coordinates 03065 double x, y, z; 03066 iMesh_getVtxCoord( imesh, vtx, &x, &y, &z, &ierr );CHKERR; 03067 assert( 0.0 == z ); 03068 const int xi = ( (int)round( x ) - 1 ) / 2; 03069 const int yi = ( (int)round( y ) - 1 ) / 2; 03070 assert( xi >= 0 ); 03071 assert( yi >= 0 ); 03072 assert( fabs( x - 2 * xi - 1 ) < 1e-12 ); 03073 assert( fabs( y - 2 * yi - 1 ) < 1e-12 ); 03074 03075 id = 2 * xi + yi; 03076 return 0; 03077 }