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