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 <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::mesh::Part;
00030 using stk::mesh::MetaData;
00031 using stk::mesh::fem::FEMMetaData;
00032 using stk::mesh::BulkData;
00033 using stk::mesh::Selector;
00034 using stk::mesh::PartVector;
00035 using stk::mesh::BaseEntityRank;
00036 using stk::mesh::PairIterRelation;
00037 using stk::mesh::EntityProc;
00038 using stk::mesh::Entity;
00039 using stk::mesh::EntityId;
00040 using stk::mesh::EntityKey;
00041 using stk::mesh::EntityVector;
00042 using stk::mesh::EntityRank;
00043 using stk::mesh::fixtures::RingFixture;
00044 using stk::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::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::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::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::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::ParallelMachine pm = MPI_COMM_WORLD;
00224   MPI_Barrier( pm );
00225 
00226   enum { nPerProc = 10 };
00227   const unsigned p_rank = stk::parallel_machine_rank( pm );
00228   const unsigned p_size = stk::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::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::ParallelMachine pm = MPI_COMM_WORLD;
00338   MPI_Barrier( pm );
00339 
00340   enum { nPerProc = 10 };
00341 
00342   const unsigned p_size = stk::parallel_machine_size( pm );
00343   const unsigned p_rank = stk::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::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::ParallelMachine pm = MPI_COMM_WORLD;
00429   MPI_Barrier( pm );
00430 
00431   enum { nPerProc = 10 };
00432   const unsigned p_rank = stk::parallel_machine_rank( pm );
00433   const unsigned p_size = stk::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::unit_test::modification_end_wrapper(bulk, aura));
00449 
00450     bulk.modification_begin();
00451     ring_mesh.fixup_node_ownership( );
00452     STKUNIT_ASSERT(stk::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::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::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::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::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::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::parallel_machine_size( pm );
00684 
00685   const int spatial_dimension = 3;
00686   MetaData meta( stk::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::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::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::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::ParallelMachine pm = MPI_COMM_WORLD;
00780   MPI_Barrier( pm );
00781 
00782   const unsigned nPerProc = 2;
00783   const unsigned p_size = stk::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::mesh::Part& special_part =
00791     ring_mesh.m_meta_data.declare_part("special_node_part", stk::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::mesh::EntityRank element_rank = ring_mesh.m_meta_data.element_rank();
00806   stk::mesh::get_entities( ring_mesh.m_bulk_data, element_rank, edges );
00807   stk::mesh::Entity& edge = *( edges.front() );
00808 
00809   // get one of the nodes related to this edge
00810   PairIterRelation node_relations = edge.relations( stk::mesh::BaseEntityRank );
00811   STKUNIT_ASSERT( !node_relations.empty() );
00812   stk::mesh::Entity& node = *( node_relations.front().entity());
00813   STKUNIT_ASSERT_EQUAL( node.entity_rank(), (unsigned) stk::mesh::BaseEntityRank );
00814 
00815   // make a modification to the node by changing its parts
00816   ring_mesh.m_bulk_data.modification_begin();
00817   stk::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::mesh::EntityLogModified );
00823   STKUNIT_ASSERT_EQUAL ( edge.log_query(), stk::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::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::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::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::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::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::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::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::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::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::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::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::mesh::Bucket& bucket = expected_ghosted_family_tree->bucket();
01336     STKUNIT_ASSERT(!bucket.member(owned) && !bucket.member(shared));
01337   }
01338 #endif
01339 }
01340 
01341 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends