|
Sierra Toolkit
Version of the Day
|
00001 /*------------------------------------------------------------------------*/ 00002 /* Copyright 2010 Sandia Corporation. */ 00003 /* Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive */ 00004 /* license for use of this work by or on behalf of the U.S. Government. */ 00005 /* Export of this program may require a license from the */ 00006 /* United States Government. */ 00007 /*------------------------------------------------------------------------*/ 00008 00009 00010 #include <iostream> 00011 #include <sstream> 00012 #include <stdexcept> 00013 00014 #include <stk_util/unit_test_support/stk_utest_macros.hpp> 00015 00016 #include <stk_util/parallel/Parallel.hpp> 00017 00018 #include <stk_mesh/base/BulkData.hpp> 00019 #include <stk_mesh/base/GetEntities.hpp> 00020 #include <stk_mesh/base/EntityComm.hpp> 00021 #include <stk_mesh/base/Comm.hpp> 00022 00023 #include <stk_mesh/fixtures/BoxFixture.hpp> 00024 #include <stk_mesh/fixtures/RingFixture.hpp> 00025 00026 #include <unit_tests/UnitTestModificationEndWrapper.hpp> 00027 #include <unit_tests/UnitTestRingFixture.hpp> 00028 00029 using stk_classic::mesh::Part; 00030 using stk_classic::mesh::MetaData; 00031 using stk_classic::mesh::fem::FEMMetaData; 00032 using stk_classic::mesh::BulkData; 00033 using stk_classic::mesh::Selector; 00034 using stk_classic::mesh::PartVector; 00035 using stk_classic::mesh::BaseEntityRank; 00036 using stk_classic::mesh::PairIterRelation; 00037 using stk_classic::mesh::EntityProc; 00038 using stk_classic::mesh::Entity; 00039 using stk_classic::mesh::EntityId; 00040 using stk_classic::mesh::EntityKey; 00041 using stk_classic::mesh::EntityVector; 00042 using stk_classic::mesh::EntityRank; 00043 using stk_classic::mesh::fixtures::RingFixture; 00044 using stk_classic::mesh::fixtures::BoxFixture; 00045 00046 namespace { 00047 00048 const EntityRank NODE_RANK = FEMMetaData::NODE_RANK; 00049 00050 void donate_one_element( BulkData & mesh , bool aura ) 00051 { 00052 const unsigned p_rank = mesh.parallel_rank(); 00053 00054 Selector select_owned( MetaData::get(mesh).locally_owned_part() ); 00055 00056 std::vector<unsigned> before_count ; 00057 std::vector<unsigned> after_count ; 00058 00059 count_entities( select_owned , mesh , before_count ); 00060 00061 // Change owner of an element on a process boundary 00062 // from P0 to P1, and then recount to confirm ownership change 00063 00064 std::vector<EntityProc> change ; 00065 00066 // A shared node: 00067 Entity * node = NULL ; 00068 Entity * elem = NULL ; 00069 00070 for ( std::vector<Entity*>::const_iterator 00071 i = mesh.entity_comm().begin() ; 00072 i != mesh.entity_comm().end() ; ++i ) { 00073 if ( in_shared( **i ) && (**i).entity_rank() == BaseEntityRank ) { 00074 node = *i ; 00075 break ; 00076 } 00077 } 00078 00079 STKUNIT_ASSERT( node != NULL ); 00080 00081 for ( PairIterRelation rel = node->relations( 3 ); 00082 ! rel.empty() && elem == NULL ; ++rel ) { 00083 elem = rel->entity(); 00084 if ( elem->owner_rank() != p_rank ) { elem = NULL ; } 00085 } 00086 00087 STKUNIT_ASSERT( elem != NULL ); 00088 00089 unsigned donated_nodes = 0 ; 00090 00091 // Only process #0 donates an element and its owned nodes: 00092 if ( 0 == p_rank ) { 00093 EntityProc entry ; 00094 entry.first = elem ; 00095 entry.second = node->sharing()[0].proc ; 00096 change.push_back( entry ); 00097 for ( PairIterRelation 00098 rel = elem->relations(0) ; ! rel.empty() ; ++rel ) { 00099 if ( rel->entity()->owner_rank() == p_rank ) { 00100 entry.first = rel->entity(); 00101 change.push_back( entry ); 00102 ++donated_nodes ; 00103 } 00104 } 00105 } 00106 00107 STKUNIT_ASSERT( mesh.modification_begin() ); 00108 mesh.change_entity_owner( change ); 00109 STKUNIT_ASSERT( stk_classic::unit_test::modification_end_wrapper( mesh , aura ) ); 00110 00111 count_entities( select_owned , mesh , after_count ); 00112 00113 if ( 0 == p_rank ) { 00114 STKUNIT_ASSERT_EQUAL( before_count[3] - 1 , after_count[3] ); 00115 STKUNIT_ASSERT_EQUAL( before_count[0] - donated_nodes, after_count[0] ); 00116 } 00117 } 00118 00119 void donate_all_shared_nodes( BulkData & mesh , bool aura ) 00120 { 00121 const unsigned p_rank = mesh.parallel_rank(); 00122 00123 const Selector select_used = MetaData::get(mesh).locally_owned_part() | 00124 MetaData::get(mesh).globally_shared_part() ; 00125 00126 std::vector<unsigned> before_count ; 00127 std::vector<unsigned> after_count ; 00128 00129 count_entities( select_used , mesh , before_count ); 00130 00131 // Donate owned shared nodes to first sharing process. 00132 00133 const std::vector<Entity*> & entity_comm = mesh.entity_comm(); 00134 00135 STKUNIT_ASSERT( ! entity_comm.empty() ); 00136 00137 std::vector<EntityProc> change ; 00138 00139 for ( std::vector<Entity*>::const_iterator 00140 i = entity_comm.begin() ; 00141 i != entity_comm.end() && 00142 (**i).entity_rank() == BaseEntityRank ; ++i ) { 00143 Entity * const node = *i ; 00144 const stk_classic::mesh::PairIterEntityComm ec = node->sharing(); 00145 00146 if ( node->owner_rank() == p_rank && ! ec.empty() ) { 00147 change.push_back( EntityProc( node , ec->proc ) ); 00148 } 00149 } 00150 00151 STKUNIT_ASSERT( mesh.modification_begin() ); 00152 mesh.change_entity_owner( change ); 00153 STKUNIT_ASSERT( stk_classic::unit_test::modification_end_wrapper( mesh , aura ) ); 00154 00155 count_entities( select_used , mesh , after_count ); 00156 00157 STKUNIT_ASSERT( 3 <= after_count.size() ); 00158 STKUNIT_ASSERT_EQUAL( before_count[0] , after_count[0] ); 00159 STKUNIT_ASSERT_EQUAL( before_count[1] , after_count[1] ); 00160 STKUNIT_ASSERT_EQUAL( before_count[2] , after_count[2] ); 00161 STKUNIT_ASSERT_EQUAL( before_count[3] , after_count[3] ); 00162 } 00163 00164 } // empty namespace 00165 00166 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, testBulkData) 00167 { 00168 // Unit test the Part functionality in isolation: 00169 00170 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 00171 MPI_Barrier( pm ); 00172 00173 std::vector<std::string> entity_names(10); 00174 for ( size_t i = 0 ; i < 10 ; ++i ) { 00175 std::ostringstream name ; 00176 name << "EntityRank" << i ; 00177 entity_names[i] = name.str(); 00178 } 00179 00180 MetaData meta( entity_names ); 00181 00182 meta.commit(); 00183 00184 BulkData bulk( meta , pm , 100 ); 00185 00186 for ( size_t i = 0 ; i < 4 ; ++i ) { 00187 STKUNIT_ASSERT( bulk.modification_begin() ); 00188 STKUNIT_ASSERT_EQUAL( i , bulk.synchronized_count() ); 00189 STKUNIT_ASSERT( bulk.modification_end() ); 00190 } 00191 00192 std::vector<Part*> no_parts ; 00193 00194 Entity * e[10] ; 00195 00196 const unsigned id = bulk.parallel_rank() + 1 ; 00197 00198 STKUNIT_ASSERT( bulk.modification_begin() ); 00199 for ( size_t i = 0 ; i < 10 ; ++i ) { 00200 e[i] = & bulk.declare_entity( i , id , no_parts ); 00201 } 00202 STKUNIT_ASSERT( bulk.modification_end() ); 00203 00204 for ( size_t i = 0 ; i < 10 ; ++i ) { 00205 STKUNIT_ASSERT( e[i] == bulk.get_entity( i , id ) ); 00206 } 00207 00208 STKUNIT_ASSERT( bulk.modification_begin() ); 00209 STKUNIT_ASSERT_THROW( bulk.declare_entity( 11 , id , no_parts ), 00210 std::logic_error ); 00211 STKUNIT_ASSERT( bulk.modification_end() ); 00212 00213 // Catch not-ok-to-modify 00214 STKUNIT_ASSERT_THROW( bulk.declare_entity( 0 , id + 1 , no_parts ), 00215 std::logic_error ); 00216 } 00217 00218 //---------------------------------------------------------------------- 00219 // Testing for mesh entities without relations 00220 00221 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, testChangeOwner_nodes) 00222 { 00223 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 00224 MPI_Barrier( pm ); 00225 00226 enum { nPerProc = 10 }; 00227 const unsigned p_rank = stk_classic::parallel_machine_rank( pm ); 00228 const unsigned p_size = stk_classic::parallel_machine_size( pm ); 00229 const unsigned id_total = nPerProc * p_size ; 00230 const unsigned id_begin = nPerProc * p_rank ; 00231 const unsigned id_end = nPerProc * ( p_rank + 1 ); 00232 00233 const int spatial_dimension = 3; 00234 MetaData meta( stk_classic::mesh::fem::entity_rank_names(spatial_dimension) ); 00235 BulkData bulk( meta , pm , 100 ); 00236 00237 const PartVector no_parts ; 00238 00239 meta.commit(); 00240 bulk.modification_begin(); 00241 00242 // Ids for all entities (all entities have type 0): 00243 00244 std::vector<EntityId> ids( id_total ); 00245 00246 for ( unsigned i = 0 ; i < id_total ; ++i ) { 00247 ids[i] = i + 1; 00248 } 00249 00250 // Declare just those entities in my range of ids: 00251 00252 for ( unsigned i = id_begin ; i < id_end ; ++i ) { 00253 bulk.declare_entity( 0 , ids[i] , no_parts ); 00254 } 00255 00256 STKUNIT_ASSERT( bulk.modification_end() ); 00257 00258 // Verify that I only have entities in my range: 00259 00260 for ( unsigned i = 0 ; i < id_total ; ++i ) { 00261 Entity * e = bulk.get_entity( 0 , ids[ i ] ); 00262 if ( id_begin <= i && i < id_end ) { 00263 STKUNIT_ASSERT( NULL != e ); 00264 } 00265 else { 00266 STKUNIT_ASSERT( NULL == e ); 00267 } 00268 } 00269 00270 // Test change owner no-op first: 00271 00272 std::vector<EntityProc> change ; 00273 00274 STKUNIT_ASSERT( bulk.modification_begin() ); 00275 bulk.change_entity_owner( change ); 00276 STKUNIT_ASSERT( bulk.modification_end() ); 00277 00278 for ( unsigned i = 0 ; i < id_total ; ++i ) { 00279 Entity * e = bulk.get_entity( 0 , ids[ i ] ); 00280 if ( id_begin <= i && i < id_end ) { 00281 STKUNIT_ASSERT( NULL != e ); 00282 } 00283 else { 00284 STKUNIT_ASSERT( NULL == e ); 00285 } 00286 } 00287 00288 // Can only test changing owner in parallel. 00289 00290 if ( 1 < p_size ) { 00291 // Give my last two ids to the next process 00292 // Get the previous process' last two ids 00293 00294 const unsigned p_give = ( p_rank + 1 ) % p_size ; 00295 const unsigned id_give = id_end - 2 ; 00296 const unsigned id_get = ( id_begin + id_total - 2 ) % id_total ; 00297 00298 STKUNIT_ASSERT( NULL != bulk.get_entity( 0 , ids[id_give] ) ); 00299 STKUNIT_ASSERT( NULL != bulk.get_entity( 0 , ids[id_give+1] ) ); 00300 STKUNIT_ASSERT( NULL == bulk.get_entity( 0 , ids[id_get] ) ); 00301 STKUNIT_ASSERT( NULL == bulk.get_entity( 0 , ids[id_get+1] ) ); 00302 00303 change.resize(2); 00304 change[0].first = bulk.get_entity( 0 , ids[id_give] ); 00305 change[0].second = p_give ; 00306 change[1].first = bulk.get_entity( 0 , ids[id_give+1] ); 00307 change[1].second = p_give ; 00308 00309 STKUNIT_ASSERT( bulk.modification_begin() ); 00310 bulk.change_entity_owner( change ); 00311 STKUNIT_ASSERT( bulk.modification_end() ); 00312 00313 STKUNIT_ASSERT( NULL != bulk.get_entity( 0 , ids[id_get] ) ); 00314 STKUNIT_ASSERT( NULL != bulk.get_entity( 0 , ids[id_get+1] ) ); 00315 00316 // Entities given away are destroyed until the next modification cycle 00317 { 00318 Entity * const e0 = bulk.get_entity( 0 , ids[id_give] ); 00319 Entity * const e1 = bulk.get_entity( 0 , ids[id_give+1] ); 00320 STKUNIT_ASSERT( NULL != e0 && e0->bucket().capacity() == 0 ); 00321 STKUNIT_ASSERT( NULL != e1 && e1->bucket().capacity() == 0 ); 00322 } 00323 00324 STKUNIT_ASSERT( bulk.modification_begin() ); 00325 STKUNIT_ASSERT( bulk.modification_end() ); 00326 00327 STKUNIT_ASSERT( NULL == bulk.get_entity( 0 , ids[id_give] ) ); 00328 STKUNIT_ASSERT( NULL == bulk.get_entity( 0 , ids[id_give+1] ) ); 00329 } 00330 } 00331 00332 //---------------------------------------------------------------------- 00333 // Testing for creating existing mesh entities without relations 00334 00335 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, testCreateMore) 00336 { 00337 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 00338 MPI_Barrier( pm ); 00339 00340 enum { nPerProc = 10 }; 00341 00342 const unsigned p_size = stk_classic::parallel_machine_size( pm ); 00343 const unsigned p_rank = stk_classic::parallel_machine_rank( pm ); 00344 00345 if ( 1 < p_size ) { 00346 00347 const unsigned id_total = nPerProc * p_size ; 00348 const unsigned id_begin = nPerProc * p_rank ; 00349 const unsigned id_end = nPerProc * ( p_rank + 1 ); 00350 00351 const int spatial_dimension = 3; 00352 MetaData meta( stk_classic::mesh::fem::entity_rank_names(spatial_dimension) ); 00353 00354 const PartVector no_parts ; 00355 00356 meta.commit(); 00357 00358 BulkData bulk( meta , pm , 100 ); 00359 00360 bulk.modification_begin(); 00361 00362 // Ids for all entities (all entities have type 0): 00363 00364 std::vector<EntityId> ids( id_total ); 00365 00366 for ( unsigned i = 0 ; i < id_total ; ++i ) { ids[i] = i + 1; } 00367 00368 // Declare just those entities in my range of ids: 00369 00370 for ( unsigned i = id_begin ; i < id_end ; ++i ) { 00371 bulk.declare_entity( 0 , ids[i] , no_parts ); 00372 } 00373 00374 STKUNIT_ASSERT( bulk.modification_end() ); 00375 00376 // Only one process create entities with previous process' last two ids 00377 00378 const unsigned id_get = ( id_begin + id_total - 2 ) % id_total ; 00379 00380 STKUNIT_ASSERT( NULL == bulk.get_entity( 0 , ids[id_get] ) ); 00381 STKUNIT_ASSERT( NULL == bulk.get_entity( 0 , ids[id_get+1] ) ); 00382 00383 STKUNIT_ASSERT( bulk.modification_begin() ); 00384 00385 if ( 1 == p_rank ) { 00386 // These declarations create entities that already exist, 00387 // which will be an error. Must create an owned entity 00388 // to use them, thus they become shared. 00389 00390 Entity & e0 = bulk.declare_entity( 0 , ids[ id_get ] , no_parts ); 00391 Entity & e1 = bulk.declare_entity( 0 , ids[ id_get + 1 ] , no_parts ); 00392 00393 Entity & eU = bulk.declare_entity( 1 , 1 , no_parts ); 00394 00395 bulk.declare_relation( eU , e0 , 0 ); 00396 bulk.declare_relation( eU , e1 , 1 ); 00397 } 00398 00399 bulk.modification_end(); 00400 00401 if ( 1 == p_rank ) { 00402 Entity * e0 = bulk.get_entity( 0 , ids[id_get] ); 00403 Entity * e1 = bulk.get_entity( 0 , ids[id_get+1] ); 00404 STKUNIT_ASSERT( NULL != e0 ); 00405 STKUNIT_ASSERT( NULL != e1 ); 00406 STKUNIT_ASSERT( 0 == e0->owner_rank() ); 00407 STKUNIT_ASSERT( 0 == e1->owner_rank() ); 00408 } 00409 00410 // Now test tripping the error condition 00411 00412 bulk.modification_begin(); 00413 00414 if ( 0 == p_rank ) { 00415 bulk.declare_entity( 0 , ids[ id_get ] , no_parts ); 00416 bulk.declare_entity( 0 , ids[ id_get + 1 ] , no_parts ); 00417 } 00418 00419 STKUNIT_ASSERT_THROW( bulk.modification_end() , std::runtime_error ); 00420 } 00421 } 00422 00423 //---------------------------------------------------------------------- 00424 //---------------------------------------------------------------------- 00425 00426 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, testChangeOwner_ring) 00427 { 00428 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 00429 MPI_Barrier( pm ); 00430 00431 enum { nPerProc = 10 }; 00432 const unsigned p_rank = stk_classic::parallel_machine_rank( pm ); 00433 const unsigned p_size = stk_classic::parallel_machine_size( pm ); 00434 const unsigned nLocalNode = nPerProc + ( 1 < p_size ? 1 : 0 ); 00435 const unsigned nLocalEdge = nPerProc ; 00436 00437 std::vector<unsigned> local_count ; 00438 00439 //------------------------------ 00440 { 00441 bool aura = false; 00442 RingFixture ring_mesh( pm , nPerProc , false /* no edge parts */ ); 00443 BulkData & bulk = ring_mesh.m_bulk_data; 00444 ring_mesh.m_meta_data.commit(); 00445 00446 bulk.modification_begin(); 00447 ring_mesh.generate_mesh( ); 00448 STKUNIT_ASSERT(stk_classic::unit_test::modification_end_wrapper(bulk, aura)); 00449 00450 bulk.modification_begin(); 00451 ring_mesh.fixup_node_ownership( ); 00452 STKUNIT_ASSERT(stk_classic::unit_test::modification_end_wrapper(bulk, aura)); 00453 00454 const Selector select_used = ring_mesh.m_meta_data.locally_owned_part() | 00455 ring_mesh.m_meta_data.globally_shared_part() ; 00456 const Selector select_all = ring_mesh.m_meta_data.universal_part() ; 00457 00458 count_entities( select_used , ring_mesh.m_bulk_data , local_count ); 00459 STKUNIT_ASSERT_EQUAL( local_count[0] , nLocalNode ); 00460 STKUNIT_ASSERT_EQUAL( local_count[1] , nLocalEdge ); 00461 00462 count_entities( select_all , ring_mesh.m_bulk_data , local_count ); 00463 STKUNIT_ASSERT_EQUAL( local_count[0] , nLocalNode ); 00464 STKUNIT_ASSERT_EQUAL( local_count[1] , nLocalEdge ); 00465 00466 if ( 1 < p_size ) { 00467 // Shift ring by two nodes and edges. 00468 00469 stk_classic::unit_test::test_shift_ring( ring_mesh, false /* no aura */ ); 00470 00471 count_entities( select_used , ring_mesh.m_bulk_data , local_count ); 00472 STKUNIT_ASSERT( local_count[0] == nLocalNode ); 00473 STKUNIT_ASSERT( local_count[1] == nLocalEdge ); 00474 00475 count_entities( select_all , ring_mesh.m_bulk_data , local_count ); 00476 STKUNIT_ASSERT( local_count[0] == nLocalNode ); 00477 STKUNIT_ASSERT( local_count[1] == nLocalEdge ); 00478 } 00479 } 00480 00481 //------------------------------ 00482 // Test shift starting with ghosting but not regenerated ghosting. 00483 { 00484 RingFixture ring_mesh( pm , nPerProc , false /* no edge parts */ ); 00485 BulkData& bulk = ring_mesh.m_bulk_data; 00486 ring_mesh.m_meta_data.commit(); 00487 00488 bulk.modification_begin(); 00489 ring_mesh.generate_mesh( ); 00490 STKUNIT_ASSERT(bulk.modification_end()); 00491 00492 bulk.modification_begin(); 00493 ring_mesh.fixup_node_ownership( ); 00494 STKUNIT_ASSERT(bulk.modification_end()); 00495 00496 const Selector select_owned( ring_mesh.m_meta_data.locally_owned_part() ); 00497 const Selector select_used = ring_mesh.m_meta_data.locally_owned_part() | 00498 ring_mesh.m_meta_data.globally_shared_part() ; 00499 const Selector select_all( ring_mesh.m_meta_data.universal_part() ); 00500 00501 count_entities( select_used , ring_mesh.m_bulk_data , local_count ); 00502 STKUNIT_ASSERT_EQUAL( local_count[0] , nLocalNode ); 00503 STKUNIT_ASSERT_EQUAL( local_count[1] , nLocalEdge ); 00504 00505 count_entities( select_all , ring_mesh.m_bulk_data , local_count ); 00506 const unsigned n_extra = 1 < p_size ? 2 : 0 ; 00507 STKUNIT_ASSERT( local_count[0] == nLocalNode + n_extra ); 00508 STKUNIT_ASSERT( local_count[1] == nLocalEdge + n_extra ); 00509 00510 if ( 1 < p_size ) { 00511 stk_classic::unit_test::test_shift_ring( ring_mesh, false /* no aura */ ); 00512 00513 count_entities( select_owned , ring_mesh.m_bulk_data , local_count ); 00514 STKUNIT_ASSERT( local_count[0] == nPerProc ); 00515 STKUNIT_ASSERT( local_count[1] == nPerProc ); 00516 00517 count_entities( select_used , ring_mesh.m_bulk_data , local_count ); 00518 STKUNIT_ASSERT( local_count[0] == nLocalNode ); 00519 STKUNIT_ASSERT( local_count[1] == nLocalEdge ); 00520 00521 // All of my ghosts were disrupted and therefore deleted: 00522 count_entities( select_all , ring_mesh.m_bulk_data , local_count ); 00523 STKUNIT_ASSERT_EQUAL( nLocalEdge , local_count[1] ); 00524 STKUNIT_ASSERT_EQUAL( nLocalNode , local_count[0] ); 00525 } 00526 } 00527 //------------------------------ 00528 // Test shift starting with ghosting and regenerating ghosting. 00529 { 00530 RingFixture ring_mesh( pm , nPerProc , false /* no edge parts */ ); 00531 BulkData& bulk = ring_mesh.m_bulk_data; 00532 ring_mesh.m_meta_data.commit(); 00533 00534 bulk.modification_begin(); 00535 ring_mesh.generate_mesh( ); 00536 STKUNIT_ASSERT(bulk.modification_end()); 00537 00538 bulk.modification_begin(); 00539 ring_mesh.fixup_node_ownership( ); 00540 STKUNIT_ASSERT(bulk.modification_end()); 00541 00542 const Selector select_owned( ring_mesh.m_meta_data.locally_owned_part() ); 00543 const Selector select_used = ring_mesh.m_meta_data.locally_owned_part() | 00544 ring_mesh.m_meta_data.globally_shared_part() ; 00545 const Selector select_all( ring_mesh.m_meta_data.universal_part() ); 00546 00547 count_entities( select_used , ring_mesh.m_bulk_data , local_count ); 00548 STKUNIT_ASSERT( local_count[0] == nLocalNode ); 00549 STKUNIT_ASSERT( local_count[1] == nLocalEdge ); 00550 00551 count_entities( select_all , ring_mesh.m_bulk_data , local_count ); 00552 const unsigned n_extra = 1 < p_size ? 2 : 0 ; 00553 STKUNIT_ASSERT( local_count[0] == nLocalNode + n_extra ); 00554 STKUNIT_ASSERT( local_count[1] == nLocalEdge + n_extra ); 00555 00556 if ( 1 < p_size ) { 00557 stk_classic::unit_test::test_shift_ring( ring_mesh, true /* with aura */ ); 00558 00559 count_entities( select_owned , ring_mesh.m_bulk_data , local_count ); 00560 STKUNIT_ASSERT( local_count[0] == nPerProc ); 00561 STKUNIT_ASSERT( local_count[1] == nPerProc ); 00562 00563 count_entities( select_used , ring_mesh.m_bulk_data , local_count ); 00564 STKUNIT_ASSERT( local_count[0] == nLocalNode ); 00565 STKUNIT_ASSERT( local_count[1] == nLocalEdge ); 00566 00567 // All of my ghosts were regenerated: 00568 count_entities( select_all , ring_mesh.m_bulk_data , local_count ); 00569 STKUNIT_ASSERT( local_count[0] == nLocalNode + n_extra ); 00570 STKUNIT_ASSERT( local_count[1] == nLocalEdge + n_extra ); 00571 } 00572 } 00573 //------------------------------ 00574 // Test bad owner change catching: 00575 if ( 1 < p_size ) { 00576 RingFixture ring_mesh( pm , nPerProc , false /* no edge parts */ ); 00577 BulkData& bulk = ring_mesh.m_bulk_data; 00578 ring_mesh.m_meta_data.commit(); 00579 00580 bulk.modification_begin(); 00581 ring_mesh.generate_mesh( ); 00582 STKUNIT_ASSERT(bulk.modification_end()); 00583 00584 bulk.modification_begin(); 00585 ring_mesh.fixup_node_ownership( ); 00586 STKUNIT_ASSERT(bulk.modification_end()); 00587 00588 std::vector<EntityProc> change ; 00589 00590 if ( 0 == p_rank ) { 00591 change.resize(4); 00592 // Error to change to bad owner: 00593 change[0].first = ring_mesh.m_bulk_data.get_entity( 0 , ring_mesh.m_node_ids[1] ); 00594 change[0].second = p_size ; 00595 // Error to change a ghost: 00596 for ( std::vector<Entity*>::const_iterator 00597 ec = ring_mesh.m_bulk_data.entity_comm().begin() ; 00598 ec != ring_mesh.m_bulk_data.entity_comm().end() ; ++ec ) { 00599 if ( in_receive_ghost( **ec ) ) { 00600 change[1].first = *ec ; 00601 break ; 00602 } 00603 } 00604 change[1].second = p_rank ; 00605 // Error to change to multiple owners: 00606 change[2].first = ring_mesh.m_bulk_data.get_entity( 0 , ring_mesh.m_node_ids[1] ); 00607 change[2].second = ( p_rank + 1 ) % p_size ; 00608 change[3].first = change[2].first ; 00609 change[3].second = ( p_rank + 2 ) % p_size ; 00610 } 00611 00612 STKUNIT_ASSERT( ring_mesh.m_bulk_data.modification_begin() ); 00613 00614 STKUNIT_ASSERT_THROW( ring_mesh.m_bulk_data.change_entity_owner( change ), 00615 std::runtime_error ); 00616 } 00617 //------------------------------ 00618 // Test move one element with initial ghosting but not regenerated ghosting: 00619 // last processor give its shared node to P0 00620 if ( 1 < p_size ) { 00621 RingFixture ring_mesh( pm , nPerProc , false /* no edge parts */ ); 00622 BulkData& bulk = ring_mesh.m_bulk_data; 00623 ring_mesh.m_meta_data.commit(); 00624 00625 bulk.modification_begin(); 00626 ring_mesh.generate_mesh( ); 00627 STKUNIT_ASSERT(bulk.modification_end()); 00628 00629 bulk.modification_begin(); 00630 ring_mesh.fixup_node_ownership( ); 00631 STKUNIT_ASSERT(bulk.modification_end()); 00632 00633 const Selector select_owned( ring_mesh.m_meta_data.locally_owned_part() ); 00634 const Selector select_used = ring_mesh.m_meta_data.locally_owned_part() | 00635 ring_mesh.m_meta_data.globally_shared_part() ; 00636 const Selector select_all( ring_mesh.m_meta_data.universal_part() ); 00637 00638 std::vector<EntityProc> change ; 00639 00640 if ( p_rank + 1 == p_size ) { 00641 EntityProc entry ; 00642 entry.first = ring_mesh.m_bulk_data.get_entity( 0 , ring_mesh.m_node_ids[0] ); 00643 entry.second = 0 ; 00644 STKUNIT_ASSERT_EQUAL( p_rank , entry.first->owner_rank() ); 00645 change.push_back( entry ); 00646 } 00647 00648 STKUNIT_ASSERT( ring_mesh.m_bulk_data.modification_begin() ); 00649 ring_mesh.m_bulk_data.change_entity_owner( change ); 00650 STKUNIT_ASSERT( stk_classic::unit_test::modification_end_wrapper( ring_mesh.m_bulk_data , false ) ); 00651 00652 count_entities( select_owned , ring_mesh.m_bulk_data , local_count ); 00653 const unsigned n_node = p_rank == 0 ? nPerProc + 1 : ( 00654 p_rank + 1 == p_size ? nPerProc - 1 : 00655 nPerProc ); 00656 00657 STKUNIT_ASSERT_EQUAL( n_node , local_count[0] ); 00658 STKUNIT_ASSERT_EQUAL( (unsigned) nPerProc , local_count[1] ); 00659 00660 count_entities( select_used , ring_mesh.m_bulk_data , local_count ); 00661 STKUNIT_ASSERT_EQUAL( nLocalNode , local_count[0] ); 00662 STKUNIT_ASSERT_EQUAL( nLocalEdge , local_count[1] ); 00663 00664 // Moving the node disrupted ghosting on first and last process 00665 count_entities( select_all , ring_mesh.m_bulk_data , local_count ); 00666 const unsigned n_extra = p_rank + 1 == p_size || p_rank == 0 ? 1 : 2 ; 00667 STKUNIT_ASSERT_EQUAL( nLocalNode + n_extra , local_count[0] ); 00668 STKUNIT_ASSERT_EQUAL( nLocalEdge + n_extra , local_count[1] ); 00669 } 00670 } 00671 00672 //---------------------------------------------------------------------- 00673 //---------------------------------------------------------------------- 00674 // Testing for collection of boxes 00675 00676 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, testChangeOwner_box) 00677 { 00678 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 00679 MPI_Barrier( pm ); 00680 00681 const int root_box[3][2] = { { 0 , 4 } , { 0 , 5 } , { 0 , 6 } }; 00682 00683 const unsigned p_size = stk_classic::parallel_machine_size( pm ); 00684 00685 const int spatial_dimension = 3; 00686 MetaData meta( stk_classic::mesh::fem::entity_rank_names(spatial_dimension) ); 00687 00688 meta.commit(); 00689 00690 //------------------------------ 00691 { 00692 bool aura = false; 00693 BoxFixture fixture( pm, 100 ); 00694 fixture.fem_meta().commit(); 00695 BulkData & bulk = fixture.bulk_data(); 00696 int local_box[3][2] = { { 0 , 0 } , { 0 , 0 } , { 0 , 0 } }; 00697 00698 bulk.modification_begin(); 00699 fixture.generate_boxes( root_box, local_box ); 00700 STKUNIT_ASSERT(stk_classic::unit_test::modification_end_wrapper(bulk, aura)); 00701 00702 if ( 1 < p_size ) { 00703 donate_one_element( bulk , aura ); 00704 } 00705 } 00706 00707 if ( 1 < p_size ) { 00708 bool aura = false; 00709 BoxFixture fixture( pm, 100 ); 00710 fixture.fem_meta().commit(); 00711 BulkData & bulk = fixture.bulk_data(); 00712 int local_box[3][2] = { { 0 , 0 } , { 0 , 0 } , { 0 , 0 } }; 00713 00714 bulk.modification_begin(); 00715 fixture.generate_boxes( root_box, local_box ); 00716 STKUNIT_ASSERT(stk_classic::unit_test::modification_end_wrapper(bulk, aura)); 00717 00718 donate_all_shared_nodes( bulk , aura ); 00719 } 00720 //------------------------------ 00721 if ( 1 < p_size ) { 00722 bool aura = false; 00723 BoxFixture fixture( pm, 100 ); 00724 fixture.fem_meta().commit(); 00725 BulkData & bulk = fixture.bulk_data(); 00726 int local_box[3][2] = { { 0 , 0 } , { 0 , 0 } , { 0 , 0 } }; 00727 00728 bulk.modification_begin(); 00729 fixture.generate_boxes( root_box, local_box ); 00730 STKUNIT_ASSERT(stk_classic::unit_test::modification_end_wrapper(bulk, aura)); 00731 00732 donate_one_element( bulk , false /* no aura */ ); 00733 } 00734 //------------------------------ 00735 // Introduce ghosts: 00736 if ( 1 < p_size ) { 00737 BoxFixture fixture( pm, 100 ); 00738 BulkData & bulk = fixture.bulk_data(); 00739 FEMMetaData & box_meta = fixture.fem_meta(); 00740 box_meta.commit(); 00741 int local_box[3][2] = { { 0 , 0 } , { 0 , 0 } , { 0 , 0 } }; 00742 00743 bulk.modification_begin(); 00744 fixture.generate_boxes( root_box, local_box ); 00745 STKUNIT_ASSERT(bulk.modification_end()); 00746 00747 std::vector<unsigned> used_count ; 00748 std::vector<unsigned> all_count ; 00749 00750 const Selector select_owned( box_meta.locally_owned_part() ); 00751 const Selector select_used = box_meta.locally_owned_part() | 00752 box_meta.globally_shared_part() ; 00753 const Selector select_all( box_meta.universal_part() ); 00754 00755 count_entities( select_all , bulk , all_count ); 00756 count_entities( select_used , bulk , used_count ); 00757 00758 STKUNIT_ASSERT( used_count[0] < all_count[0] ); 00759 STKUNIT_ASSERT( used_count[3] < all_count[3] ); 00760 00761 donate_all_shared_nodes( bulk , false /* don't regenerate aura */ ); 00762 00763 count_entities( select_all , bulk , all_count ); 00764 count_entities( select_used , bulk , used_count ); 00765 00766 STKUNIT_ASSERT_EQUAL( used_count[0] , all_count[0] ); 00767 STKUNIT_ASSERT_EQUAL( used_count[3] , all_count[3] ); 00768 } 00769 } 00770 00771 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, testModifyPropagation) 00772 { 00773 // Our new modification model makes it so the modified status 00774 // of an entity is propagated up to higher-ranked entities 00775 // that have relations to the modified entity. We test this 00776 // by grabbing a node off of a ring mesh, modifying it, and 00777 // checking that its edge also gets marked as modified. 00778 00779 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 00780 MPI_Barrier( pm ); 00781 00782 const unsigned nPerProc = 2; 00783 const unsigned p_size = stk_classic::parallel_machine_size( pm ); 00784 00785 // this test only needs to be run w/ one processor 00786 if (p_size > 1) return; 00787 00788 // Make a ring_mesh and add an extra part 00789 RingFixture ring_mesh( pm , nPerProc, false /* don't use edge parts */); 00790 stk_classic::mesh::Part& special_part = 00791 ring_mesh.m_meta_data.declare_part("special_node_part", stk_classic::mesh::BaseEntityRank ); 00792 ring_mesh.m_meta_data.commit(); 00793 BulkData& bulk = ring_mesh.m_bulk_data; 00794 00795 bulk.modification_begin(); 00796 ring_mesh.generate_mesh( ); 00797 STKUNIT_ASSERT(bulk.modification_end()); 00798 00799 bulk.modification_begin(); 00800 ring_mesh.fixup_node_ownership( ); 00801 STKUNIT_ASSERT(bulk.modification_end()); 00802 00803 // grab the first edge 00804 EntityVector edges; 00805 const stk_classic::mesh::EntityRank element_rank = ring_mesh.m_meta_data.element_rank(); 00806 stk_classic::mesh::get_entities( ring_mesh.m_bulk_data, element_rank, edges ); 00807 stk_classic::mesh::Entity& edge = *( edges.front() ); 00808 00809 // get one of the nodes related to this edge 00810 PairIterRelation node_relations = edge.relations( stk_classic::mesh::BaseEntityRank ); 00811 STKUNIT_ASSERT( !node_relations.empty() ); 00812 stk_classic::mesh::Entity& node = *( node_relations.front().entity()); 00813 STKUNIT_ASSERT_EQUAL( node.entity_rank(), (unsigned) stk_classic::mesh::BaseEntityRank ); 00814 00815 // make a modification to the node by changing its parts 00816 ring_mesh.m_bulk_data.modification_begin(); 00817 stk_classic::mesh::PartVector parts; 00818 parts.push_back( &special_part ); 00819 ring_mesh.m_bulk_data.change_entity_parts( node, parts ); 00820 00821 // check that the node AND it's edge are marked as modified 00822 STKUNIT_ASSERT_EQUAL ( node.log_query(), stk_classic::mesh::EntityLogModified ); 00823 STKUNIT_ASSERT_EQUAL ( edge.log_query(), stk_classic::mesh::EntityLogModified ); 00824 00825 STKUNIT_ASSERT ( ring_mesh.m_bulk_data.modification_end() ); 00826 } 00827 00828 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, testChangeEntityOwnerFromSelfToSelf) 00829 { 00830 // It should be legal to "change" entity ownership from yourself to yourself. 00831 // 00832 // 1---3---5 00833 // | 1 | 2 | 00834 // 2---4---6 00835 // 00836 // To test this, we use the mesh above, with elem 1 going on rank 0 and 00837 // elem 2 going on rank 1. Nodes 3,4 are shared. After the mesh is set up 00838 // we change the ownership of a few nodes to the same proc that already 00839 // owns them. 00840 00841 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 00842 00843 // Set up meta and bulk data 00844 const unsigned spatial_dim = 2; 00845 FEMMetaData meta_data(spatial_dim); 00846 meta_data.commit(); 00847 BulkData mesh(FEMMetaData::get_meta_data(meta_data), pm); 00848 unsigned p_rank = mesh.parallel_rank(); 00849 unsigned p_size = mesh.parallel_size(); 00850 00851 // Bail if we only have one proc 00852 if (p_size == 1) { 00853 return; 00854 } 00855 00856 // Begin modification cycle so we can create the entities and relations 00857 mesh.modification_begin(); 00858 00859 EntityVector nodes; 00860 const unsigned nodes_per_elem = 4, nodes_per_side = 2; 00861 00862 if (p_rank < 2) { 00863 // We're just going to add everything to the universal part 00864 stk_classic::mesh::PartVector empty_parts; 00865 00866 // Create element 00867 const EntityRank elem_rank = meta_data.element_rank(); 00868 Entity & elem = mesh.declare_entity(elem_rank, 00869 p_rank+1, //elem_id 00870 empty_parts); 00871 00872 // Create nodes 00873 const unsigned starting_node_id = p_rank * nodes_per_side + 1; 00874 for (unsigned id = starting_node_id; id < starting_node_id + nodes_per_elem; ++id) { 00875 nodes.push_back(&mesh.declare_entity(NODE_RANK, 00876 id, 00877 empty_parts)); 00878 } 00879 00880 // Add relations to nodes 00881 unsigned rel_id = 0; 00882 for (EntityVector::iterator itr = nodes.begin(); itr != nodes.end(); ++itr, ++rel_id) { 00883 mesh.declare_relation( elem, **itr, rel_id ); 00884 } 00885 } 00886 00887 mesh.modification_end(); 00888 00889 mesh.modification_begin(); 00890 00891 std::vector<EntityProc> change ; 00892 if (p_rank < 2) { 00893 // Change ownership of some nodes to the same proc that owns them 00894 00895 // Add a non-shared node to change list 00896 if ( p_rank == 0 ) { 00897 EntityProc entry( nodes.front(), p_rank ) ; 00898 change.push_back( entry ); 00899 } 00900 else { 00901 EntityProc entry( nodes.back(), p_rank ) ; 00902 change.push_back( entry ); 00903 } 00904 00905 // Add a shared node to change list 00906 Entity* shared_node = nodes[p_rank == 0 ? nodes_per_side : 0]; 00907 EntityId expected_id = 3; 00908 Part& shared_part = meta_data.globally_shared_part(); 00909 STKUNIT_ASSERT( has_superset(shared_node->bucket(), shared_part) ); 00910 STKUNIT_ASSERT_EQUAL(shared_node->identifier(), expected_id); 00911 if (shared_node->owner_rank() == p_rank) { 00912 EntityProc entry( shared_node, p_rank ); 00913 change.push_back( entry ); 00914 } 00915 } 00916 00917 mesh.change_entity_owner(change); 00918 00919 mesh.modification_end(); 00920 } 00921 00922 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, testChangeEntityOwnerOfShared) 00923 { 00924 // This unit-test is designed to test the conditions that results that 00925 // resulted in the difficult-to-fix rebalance use-case bug. Specifically, 00926 // it will test the changing-of-ownership of a shared edge to a proc that 00927 // either ghosted it or did not know about it. 00928 // 00929 // 1---3---5---7 00930 // | 1 | 2 | 3 | ... 00931 // 2---4---6---8 00932 // 00933 // To test this, we use the mesh above, with each elem going on a separate 00934 // proc, one elem per proc. We will take the edge shared by the last 00935 // two (rightmost) elements and change the ownership to proc 0. 00936 00937 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 00938 00939 // Set up meta and bulk data 00940 const unsigned spatial_dim = 2; 00941 FEMMetaData meta_data(spatial_dim); 00942 meta_data.commit(); 00943 BulkData mesh(FEMMetaData::get_meta_data(meta_data), pm); 00944 unsigned p_rank = mesh.parallel_rank(); 00945 unsigned p_size = mesh.parallel_size(); 00946 const EntityRank edge_rank = meta_data.edge_rank(); 00947 const EntityRank elem_rank = meta_data.element_rank(); 00948 00949 // Bail if we have fewer than 3 procs 00950 if (p_size < 3) { 00951 return; 00952 } 00953 00954 // Begin modification cycle so we can create the entities and relations 00955 mesh.modification_begin(); 00956 00957 const unsigned nodes_per_elem = 4, nodes_per_side = 2; 00958 EntityKey elem_key_chg_own(elem_rank, p_size - 1 /*id*/); 00959 EntityKey edge_key_chg_own(edge_rank, 1 /*id*/); 00960 00961 // We're just going to add everything to the universal part 00962 stk_classic::mesh::PartVector empty_parts; 00963 00964 // Create element 00965 Entity & elem = mesh.declare_entity(elem_rank, 00966 p_rank+1, //elem_id 00967 empty_parts); 00968 00969 // If it is 2nd to last element, it is the one changing 00970 if (p_rank == p_size - 2) { 00971 STKUNIT_ASSERT(elem_key_chg_own == elem.key()); 00972 } 00973 00974 // Create nodes 00975 EntityVector nodes; 00976 const unsigned starting_node_id = p_rank * nodes_per_side + 1; 00977 for (unsigned id = starting_node_id; id < starting_node_id + nodes_per_elem; ++id) { 00978 nodes.push_back(&mesh.declare_entity(NODE_RANK, 00979 id, 00980 empty_parts)); 00981 } 00982 00983 // Add relations to nodes 00984 unsigned rel_id = 0; 00985 for (EntityVector::iterator itr = nodes.begin(); itr != nodes.end(); ++itr, ++rel_id) { 00986 mesh.declare_relation( elem, **itr, rel_id ); 00987 } 00988 00989 // Create edge on last two procs 00990 00991 if (p_rank >= p_size - 2) { 00992 Entity& edge = mesh.declare_entity(edge_rank, 00993 1, // id 00994 empty_parts); 00995 STKUNIT_ASSERT(edge.key() == edge_key_chg_own); 00996 00997 // Add relation from elem to edge 00998 mesh.declare_relation( elem, edge, 1 /*rel-id*/); 00999 01000 // Add relations from edge to nodes 01001 unsigned start_idx = p_rank == p_size - 1 ? 0 : nodes_per_side; 01002 unsigned end_idx = start_idx + nodes_per_side; 01003 rel_id = 0; 01004 for (unsigned idx = start_idx ; 01005 start_idx < end_idx; 01006 ++start_idx, ++rel_id) { 01007 mesh.declare_relation( edge, *nodes[idx], rel_id ); 01008 } 01009 } 01010 01011 mesh.modification_end(); 01012 01013 // Changing elem and edge should be ghosted or unknown on proc 0 01014 if (p_rank == 0) { 01015 // Get the two entities 01016 Entity* changing_elem = mesh.get_entity(elem_key_chg_own); 01017 Entity* changing_edge = mesh.get_entity(edge_key_chg_own); 01018 if (p_size == 3) { 01019 // Should be ghosted 01020 STKUNIT_ASSERT(changing_elem != NULL); 01021 STKUNIT_ASSERT(changing_edge != NULL); 01022 01023 // Verify that the entities are ghosted 01024 Part& owned = meta_data.locally_owned_part(); 01025 Part& shared = meta_data.globally_shared_part(); 01026 STKUNIT_ASSERT(!(changing_elem->bucket().member(owned) || 01027 changing_elem->bucket().member(shared))); 01028 STKUNIT_ASSERT(!(changing_edge->bucket().member(owned) || 01029 changing_edge->bucket().member(shared))); 01030 } 01031 else { 01032 // Should be NULL 01033 STKUNIT_ASSERT(changing_elem == NULL); 01034 STKUNIT_ASSERT(changing_edge == NULL); 01035 } 01036 } 01037 01038 mesh.modification_begin(); 01039 01040 std::vector<EntityProc> change ; 01041 if (p_rank >= p_size - 2) { 01042 // Change ownership of changing elem and all entities in it's closure that 01043 // we own to proc 0. 01044 01045 Entity* changing_elem = mesh.get_entity(elem_key_chg_own); 01046 if (p_rank == p_size - 2) { 01047 EntityProc eproc(changing_elem, 0 /*new owner*/); 01048 change.push_back(eproc); 01049 } 01050 01051 for (PairIterRelation i = changing_elem->relations() ; !i.empty() ; ++i) { 01052 if (i->entity()->owner_rank() == p_rank) { 01053 EntityProc eproc(i->entity(), 0 /*new owner*/); 01054 change.push_back(eproc); 01055 } 01056 } 01057 } 01058 01059 mesh.change_entity_owner(change); 01060 01061 mesh.modification_end(); 01062 01063 // Changing elem and edge should now be owned by proc 0 01064 if (p_rank == 0) { 01065 // Get the two ghosted entities, check that they were found 01066 Entity* changing_elem = mesh.get_entity(elem_key_chg_own); 01067 Entity* changing_edge = mesh.get_entity(edge_key_chg_own); 01068 STKUNIT_ASSERT(changing_elem != NULL); 01069 STKUNIT_ASSERT(changing_edge != NULL); 01070 01071 // Verify that the entities are ghosted 01072 Part& owned = meta_data.locally_owned_part(); 01073 STKUNIT_ASSERT( changing_elem->bucket().member(owned) ); 01074 STKUNIT_ASSERT( changing_edge->bucket().member(owned) ); 01075 } 01076 } 01077 01078 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, testFamilyTreeGhosting) 01079 { 01080 // A family tree is a higher-rank entity (rank = element_rank() + 1) that 01081 // has down-relations to elements used, for example, to hold parent/child 01082 // relations in an adapted mesh. 01083 // 01084 // 1---3---5---7 01085 // | 1 | 2 | 3 | ... 01086 // 2---4---6---8 01087 // 01088 // To test this, we use the mesh above, with each elem going on a separate 01089 // proc, one elem per proc. 01090 // After the mesh is set up we add rank-3 (family tree) entities and have them point down to 01091 // just the single rank-2 elements. Then we check that they are properly 01092 // ghosted after modification_end. 01093 01094 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 01095 01096 // Set up meta and bulk data 01097 const unsigned spatial_dim = 2; 01098 01099 std::vector<std::string> entity_rank_names = stk_classic::mesh::fem::entity_rank_names(spatial_dim); 01100 entity_rank_names.push_back("FAMILY_TREE"); 01101 01102 FEMMetaData meta_data(spatial_dim, entity_rank_names); 01103 meta_data.commit(); 01104 BulkData mesh(FEMMetaData::get_meta_data(meta_data), pm); 01105 unsigned p_rank = mesh.parallel_rank(); 01106 unsigned p_size = mesh.parallel_size(); 01107 01108 Part& owned = meta_data.locally_owned_part(); 01109 Part& shared = meta_data.globally_shared_part(); 01110 01111 // 01112 // Begin modification cycle so we can create the entities and relations 01113 // 01114 01115 mesh.modification_begin(); 01116 01117 EntityVector nodes; 01118 const unsigned nodes_per_elem = 4, nodes_per_side = 2; 01119 const EntityRank family_tree_rank = meta_data.element_rank() + 1; 01120 const EntityId my_family_tree_id = p_rank+1; 01121 01122 // We're just going to add everything to the universal part 01123 stk_classic::mesh::PartVector empty_parts; 01124 01125 // Create element 01126 const EntityRank elem_rank = meta_data.element_rank(); 01127 Entity & elem = mesh.declare_entity(elem_rank, 01128 p_rank+1, //elem_id 01129 empty_parts); 01130 01131 // Create nodes 01132 const unsigned starting_node_id = p_rank * nodes_per_side + 1; 01133 for (unsigned id = starting_node_id; id < starting_node_id + nodes_per_elem; ++id) { 01134 nodes.push_back(&mesh.declare_entity(NODE_RANK, 01135 id, 01136 empty_parts)); 01137 } 01138 01139 // Add relations to nodes 01140 unsigned rel_id = 0; 01141 for (EntityVector::iterator itr = nodes.begin(); itr != nodes.end(); ++itr, ++rel_id) { 01142 mesh.declare_relation( elem, **itr, rel_id ); 01143 } 01144 01145 // Create family tree 01146 Entity & family_tree = mesh.declare_entity(family_tree_rank, 01147 my_family_tree_id, 01148 empty_parts); 01149 // Add relation to element 01150 unsigned downward_ordinal = 0; // we only have 1 down relation, it has ordinal 0 01151 mesh.declare_relation( family_tree, elem, downward_ordinal); 01152 01153 mesh.modification_end(); 01154 01155 // 01156 // Test correctness of ghosting: Check that adjacent family-trees are ghosted on this proc 01157 // 01158 01159 // Compute and store ids of adjacent family-trees 01160 std::vector<EntityId> family_tree_ghost_ids; 01161 if (p_rank > 0) { 01162 family_tree_ghost_ids.push_back(my_family_tree_id - 1); 01163 } 01164 if (p_rank < p_size - 1) { 01165 family_tree_ghost_ids.push_back(my_family_tree_id + 1); 01166 } 01167 01168 // Check that my_family_tree exists and I own it 01169 Entity *my_family_tree = mesh.get_entity(family_tree_rank, my_family_tree_id); 01170 STKUNIT_ASSERT(my_family_tree); 01171 STKUNIT_ASSERT( (p_rank) == my_family_tree->owner_rank()); 01172 01173 // Check that adjacent family-trees exist and are ghosted 01174 for (std::vector<EntityId>::const_iterator 01175 itr = family_tree_ghost_ids.begin(); itr != family_tree_ghost_ids.end(); ++itr) { 01176 EntityId expected_ghosted_family_tree_id = *itr; 01177 01178 Entity *expected_ghosted_family_tree = mesh.get_entity(family_tree_rank, expected_ghosted_family_tree_id); 01179 STKUNIT_ASSERT(expected_ghosted_family_tree); 01180 STKUNIT_ASSERT(expected_ghosted_family_tree_id - 1 == expected_ghosted_family_tree->owner_rank()); 01181 01182 stk_classic::mesh::Bucket& bucket = expected_ghosted_family_tree->bucket(); 01183 STKUNIT_ASSERT(!bucket.member(owned) && !bucket.member(shared)); 01184 } 01185 } 01186 01187 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, test_other_ghosting) 01188 { 01189 // 01190 // 1---3---5---7 01191 // | 1 | 2 | 3 | ... 01192 // 2---4---6---8 01193 // 01194 // To test this, we use the mesh above, with each elem going on a separate 01195 // proc, one elem per proc. 01196 01197 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 01198 01199 // Set up meta and bulk data 01200 const unsigned spatial_dim = 2; 01201 01202 std::vector<std::string> entity_rank_names = stk_classic::mesh::fem::entity_rank_names(spatial_dim); 01203 //entity_rank_names.push_back("FAMILY_TREE"); 01204 01205 FEMMetaData meta_data(spatial_dim, entity_rank_names); 01206 meta_data.commit(); 01207 BulkData mesh(FEMMetaData::get_meta_data(meta_data), pm); 01208 unsigned p_rank = mesh.parallel_rank(); 01209 unsigned p_size = mesh.parallel_size(); 01210 01211 if (p_size != 3) return; 01212 01213 //Part& owned = meta_data.locally_owned_part(); 01214 //Part& shared = meta_data.globally_shared_part(); 01215 01216 // 01217 // Begin modification cycle so we can create the entities and relations 01218 // 01219 01220 mesh.modification_begin(); 01221 01222 EntityVector nodes; 01223 const unsigned nodes_per_elem = 4, nodes_per_side = 2; 01224 01225 // We're just going to add everything to the universal part 01226 stk_classic::mesh::PartVector empty_parts; 01227 01228 // Create element 01229 const EntityRank elem_rank = meta_data.element_rank(); 01230 Entity & elem = mesh.declare_entity(elem_rank, 01231 p_rank+1, //elem_id 01232 empty_parts); 01233 01234 // Create nodes 01235 const unsigned starting_node_id = p_rank * nodes_per_side + 1; 01236 for (unsigned id = starting_node_id; id < starting_node_id + nodes_per_elem; ++id) { 01237 nodes.push_back(&mesh.declare_entity(NODE_RANK, 01238 id, 01239 empty_parts)); 01240 std::cout << "P[" << p_rank << "] node id= " << id << std::endl; 01241 } 01242 01243 // Add relations to nodes 01244 unsigned rel_id = 0; 01245 for (EntityVector::iterator itr = nodes.begin(); itr != nodes.end(); ++itr, ++rel_id) { 01246 mesh.declare_relation( elem, **itr, rel_id ); 01247 } 01248 01249 if (1 && p_rank == 2) 01250 { 01251 Entity& node = mesh.declare_entity(NODE_RANK, 01252 4, 01253 empty_parts); 01254 //Entity* node = mesh.get_entity(NODE_RANK, 01255 //4); 01256 01257 mesh.declare_relation(elem, node, 4); 01258 } 01259 01260 mesh.modification_end(); 01261 01262 if (p_rank == 0) 01263 { 01264 unsigned id=4; 01265 Entity *node = mesh.get_entity(0, id); 01266 std::cout << "P[" << p_rank << "] node " << node << " own= " << node->owner_rank() << std::endl; 01267 01268 { 01269 PairIterRelation rels = node->relations(); 01270 for (unsigned i = 0; i < rels.size(); i++) 01271 { 01272 std::cout << "P[" << p_rank << "] rel = " << rels[i].entity()->owner_rank() << std::endl; 01273 } 01274 } 01275 } 01276 01277 mesh.modification_begin(); 01278 if (p_rank == 1) 01279 { 01280 Entity *this_elem = mesh.get_entity(2, 2); 01281 if (!mesh.destroy_entity(this_elem)) exit(2); 01282 } 01283 if (p_rank == 2) 01284 { 01285 Entity *this_elem = mesh.get_entity(2, 3); 01286 if (!mesh.destroy_entity(this_elem)) exit(2); 01287 } 01288 mesh.modification_end(); 01289 01290 if (1 || p_rank == 2) 01291 { 01292 unsigned id=4; 01293 Entity *node = mesh.get_entity(0, id); 01294 // 01295 01296 { 01297 PairIterRelation rels = node->relations(); 01298 for (unsigned i = 0; i < rels.size(); i++) 01299 { 01300 std::cout << "P[" << p_rank << "] node " << node << " own= " << node->owner_rank() << " rel = " << rels[i].entity()->owner_rank() << std::endl; 01301 } 01302 } 01303 } 01304 01305 //exit(123); 01306 01307 #if 0 01308 // 01309 // Test correctness of ghosting: Check that adjacent family-trees are ghosted on this proc 01310 // 01311 01312 // Compute and store ids of adjacent family-trees 01313 std::vector<EntityId> family_tree_ghost_ids; 01314 if (p_rank > 0) { 01315 family_tree_ghost_ids.push_back(my_family_tree_id - 1); 01316 } 01317 if (p_rank < p_size - 1) { 01318 family_tree_ghost_ids.push_back(my_family_tree_id + 1); 01319 } 01320 01321 // Check that my_family_tree exists and I own it 01322 Entity *my_family_tree = mesh.get_entity(family_tree_rank, my_family_tree_id); 01323 STKUNIT_ASSERT(my_family_tree); 01324 STKUNIT_ASSERT( (p_rank) == my_family_tree->owner_rank()); 01325 01326 // Check that adjacent family-trees exist and are ghosted 01327 for (std::vector<EntityId>::const_iterator 01328 itr = family_tree_ghost_ids.begin(); itr != family_tree_ghost_ids.end(); ++itr) { 01329 EntityId expected_ghosted_family_tree_id = *itr; 01330 01331 Entity *expected_ghosted_family_tree = mesh.get_entity(family_tree_rank, expected_ghosted_family_tree_id); 01332 STKUNIT_ASSERT(expected_ghosted_family_tree); 01333 STKUNIT_ASSERT(expected_ghosted_family_tree_id - 1 == expected_ghosted_family_tree->owner_rank()); 01334 01335 stk_classic::mesh::Bucket& bucket = expected_ghosted_family_tree->bucket(); 01336 STKUNIT_ASSERT(!bucket.member(owned) && !bucket.member(shared)); 01337 } 01338 #endif 01339 } 01340 01341 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, testChangeEntityPartsOfShared) 01342 { 01343 // 01344 // This unit-test is designed to test what happens when a shared entity 01345 // is moved on one processor during the same modification cycle in which 01346 // it was declared. 01347 // 01348 // 1---3---5 01349 // | 1 | 2 | 01350 // 2---4---6 01351 // 01352 // To test this, we use the mesh above, with each elem going on a separate 01353 // proc, one elem per proc. Node 3 is the node we'll be testing. 01354 // 01355 01356 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 01357 01358 // Set up meta and bulk data 01359 const unsigned spatial_dim = 2; 01360 FEMMetaData meta_data(spatial_dim); 01361 const EntityRank node_rank = meta_data.node_rank(); 01362 const EntityRank elem_rank = meta_data.element_rank(); 01363 01364 stk_classic::mesh::Part& extra_node_part = meta_data.declare_part("extra_node_part", node_rank); 01365 meta_data.commit(); 01366 01367 BulkData mesh(FEMMetaData::get_meta_data(meta_data), pm); 01368 unsigned p_rank = mesh.parallel_rank(); 01369 unsigned p_size = mesh.parallel_size(); 01370 01371 // Bail unless in parallel 01372 if (p_size == 1) { 01373 return; 01374 } 01375 01376 // Begin modification cycle so we can create the entities and relations 01377 if (p_rank < 2) { 01378 mesh.modification_begin(); 01379 01380 const unsigned nodes_per_elem = 4, nodes_per_side = 2; 01381 EntityKey node_key_to_move(node_rank, 3 /*id*/); 01382 01383 // We're just going to add everything to the universal part 01384 stk_classic::mesh::PartVector empty_parts; 01385 01386 // Create element 01387 Entity & elem = mesh.declare_entity(elem_rank, 01388 p_rank+1, //elem_id 01389 empty_parts); 01390 01391 // Create nodes 01392 EntityVector nodes; 01393 const unsigned starting_node_id = p_rank * nodes_per_side + 1; 01394 for (unsigned id = starting_node_id; id < starting_node_id + nodes_per_elem; ++id) { 01395 nodes.push_back(&mesh.declare_entity(NODE_RANK, 01396 id, 01397 empty_parts)); 01398 } 01399 01400 // Add relations to nodes 01401 unsigned rel_id = 0; 01402 for (EntityVector::iterator itr = nodes.begin(); itr != nodes.end(); ++itr, ++rel_id) { 01403 mesh.declare_relation( elem, **itr, rel_id ); 01404 } 01405 01406 // On the processor that does *not* end up as the owner of the node, change its parts 01407 Entity& changing_node = *mesh.get_entity(node_key_to_move); 01408 if (p_rank == 0) { 01409 PartVector add_parts(1, &extra_node_part); 01410 mesh.change_entity_parts(changing_node, add_parts); 01411 } 01412 01413 mesh.modification_end(); 01414 01415 // Expect that this is a shared node 01416 STKUNIT_EXPECT_FALSE(changing_node.sharing().empty()); 01417 01418 // Expect that part change had no impact since it was on the proc that did not end 01419 // up as the owner 01420 STKUNIT_EXPECT_FALSE(changing_node.bucket().member(extra_node_part)); 01421 01422 mesh.modification_begin(); 01423 01424 // On the processor that owns the node, change its parts 01425 if (p_rank == 1) { 01426 PartVector add_parts(1, &extra_node_part); 01427 mesh.change_entity_parts(changing_node, add_parts); 01428 } 01429 01430 mesh.modification_end(); 01431 01432 // Expect that the part change *did* have an impact 01433 STKUNIT_EXPECT_TRUE(changing_node.bucket().member(extra_node_part)); 01434 } 01435 else { 01436 // On extra procs, do bare minimum 01437 mesh.modification_begin(); 01438 mesh.modification_end(); 01439 mesh.modification_begin(); 01440 mesh.modification_end(); 01441 } 01442 } 01443 01444 STKUNIT_UNIT_TEST(UnitTestingOfBulkData, test_final_modification_end) 01445 { 01446 stk_classic::ParallelMachine pm = MPI_COMM_WORLD; 01447 01448 const unsigned spatial_dim = 2; 01449 FEMMetaData meta_data(spatial_dim); 01450 meta_data.commit(); 01451 01452 BulkData mesh(FEMMetaData::get_meta_data(meta_data), pm); 01453 01454 mesh.modification_begin(); 01455 mesh.final_modification_end(); 01456 01457 STKUNIT_ASSERT_THROW(mesh.modification_begin(), std::logic_error ); 01458 01459 }