Sierra Toolkit Version of the Day
BulkData.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 
00013 #include <stdexcept>
00014 #include <iostream>
00015 #include <sstream>
00016 #include <algorithm>
00017 
00018 #include <stk_util/util/StaticAssert.hpp>
00019 #include <stk_util/parallel/ParallelComm.hpp>
00020 #include <stk_util/parallel/ParallelReduce.hpp>
00021 #include <stk_mesh/base/Bucket.hpp>
00022 #include <stk_mesh/base/BulkData.hpp>
00023 #include <stk_mesh/base/MetaData.hpp>
00024 #include <stk_mesh/base/Comm.hpp>
00025 #include <stk_mesh/base/FieldData.hpp>
00026 
00027 namespace stk {
00028 namespace mesh {
00029 
00030 namespace {
00031 
00032 std::vector< parallel::DistributedIndex::KeySpan>
00033 convert_entity_keys_to_spans( const MetaData & meta )
00034 {
00035   // Make sure the distributed index can handle the EntityKey
00036 
00037   enum { OK = StaticAssert<
00038                 SameType< EntityKey::raw_key_type,
00039                           parallel::DistributedIndex::KeyType >::value >::OK };
00040 
00041   // Default constructed EntityKey has all bits set.
00042 
00043   const EntityKey invalid_key ;
00044   const EntityId  min_id = 1 ;
00045   const EntityId  max_id = invalid_key.id();
00046 
00047   const size_t rank_count = meta.entity_rank_count();
00048 
00049   std::vector< parallel::DistributedIndex::KeySpan> spans( rank_count );
00050 
00051   for ( size_t rank = 0 ; rank < rank_count ; ++rank ) {
00052     EntityKey key_min( rank , min_id );
00053     EntityKey key_max( rank , max_id );
00054     spans[rank].first  = key_min.raw_key();
00055     spans[rank].second = key_max.raw_key();
00056   }
00057 
00058   return spans ;
00059 }
00060 
00061 }
00062 
00063 //----------------------------------------------------------------------
00064 
00065 BulkData::BulkData( const MetaData & mesh_meta_data ,
00066                     ParallelMachine parallel ,
00067                     unsigned bucket_max_size )
00068   : m_entities_index( parallel, convert_entity_keys_to_spans(mesh_meta_data) ),
00069     m_entity_repo(),
00070     m_bucket_repository(
00071         *this, bucket_max_size,
00072         mesh_meta_data.entity_rank_count(),
00073         m_entity_repo
00074         ),
00075     m_entity_comm(),
00076     m_ghosting(),
00077 
00078     m_mesh_meta_data( mesh_meta_data ),
00079     m_parallel_machine( parallel ),
00080     m_parallel_size( parallel_machine_size( parallel ) ),
00081     m_parallel_rank( parallel_machine_rank( parallel ) ),
00082     m_sync_count( 0 ),
00083     m_sync_state( MODIFIABLE ),
00084     m_meta_data_verified( false )
00085 {
00086   create_ghosting( std::string("shared") );
00087   create_ghosting( std::string("shared_aura") );
00088 
00089   m_sync_state = SYNCHRONIZED ;
00090 }
00091 
00092 BulkData::~BulkData()
00093 {
00094   try {
00095     while ( ! m_ghosting.empty() ) {
00096       delete m_ghosting.back();
00097       m_ghosting.pop_back();
00098     }
00099   } catch(...){}
00100 
00101   try { m_entity_comm.clear(); } catch(...){}
00102 
00103 }
00104 
00105 //----------------------------------------------------------------------
00106 //----------------------------------------------------------------------
00107 
00108 void BulkData::assert_ok_to_modify( const char * method ) const
00109 {
00110   if ( m_sync_state == SYNCHRONIZED ) {
00111     std::string msg( method );
00112     msg.append( ": FAILED, NOT in the ok-to-modify state" );
00113     throw std::runtime_error( msg );
00114   }
00115 }
00116 
00117 void BulkData::assert_entity_owner( const char * method ,
00118                                     const Entity & e ,
00119                                     unsigned owner ) const
00120 {
00121   const bool error_not_owner = owner != e.owner_rank() ;
00122 
00123   if ( error_not_owner ) {
00124     std::ostringstream msg ;
00125     msg << method << "( " ;
00126     print_entity_key( msg , m_mesh_meta_data , e.key() );
00127     msg << " ) FAILED" ;
00128 
00129     msg << " : Owner( " << e.owner_rank()
00130         << " ) != Required( " << owner << " )" ;
00131 
00132     throw std::runtime_error( msg.str() );
00133   }
00134 }
00135 
00136 void BulkData::assert_good_key( const char * method ,
00137                                 const EntityKey & key ) const
00138 {
00139   const size_t rank_count = m_mesh_meta_data.entity_rank_count();
00140   const bool ok_id   = 0 < entity_id( key );
00141   const bool ok_type = entity_rank( key ) < rank_count ;
00142 
00143   if ( ! ok_type || ! ok_id ) {
00144     std::ostringstream msg ;
00145     msg << method ;
00146     msg << "( " ;
00147     if ( ! ok_type ) {
00148       msg << entity_rank( key ) << "-"
00149           << entity_id( key ) << " : BAD KEY TYPE" ;
00150     }
00151     else {
00152       print_entity_key( msg , m_mesh_meta_data , key );
00153       msg << " : BAD KEY ID" ;
00154     }
00155     msg << " ) FAILED" ;
00156     throw std::runtime_error( msg.str() );
00157   }
00158 }
00159 
00160 //----------------------------------------------------------------------
00161 
00162 bool BulkData::modification_begin()
00163 {
00164   static const char method[] = "stk::mesh::BulkData::modification_begin" ;
00165 
00166   parallel_machine_barrier( m_parallel_machine );
00167 
00168   if ( m_sync_state == MODIFIABLE ) return false ;
00169 
00170   if ( ! m_meta_data_verified ) {
00171     m_mesh_meta_data.assert_committed( method );
00172 
00173     verify_parallel_consistency( m_mesh_meta_data , m_parallel_machine );
00174 
00175     m_meta_data_verified = true ;
00176 
00177     m_bucket_repository.declare_nil_bucket();
00178   }
00179   else {
00180     ++m_sync_count ;
00181 
00182     // Clear out the previous transaction information
00183     // m_transaction_log.flush();
00184 
00185     m_entity_repo.clean_changes();
00186   }
00187 
00188   m_sync_state = MODIFIABLE ;
00189 
00190   return true ;
00191 }
00192 
00193 
00194 //----------------------------------------------------------------------
00195 
00196 
00197 void BulkData::verify_type_and_id(const char* calling_method,
00198                                   EntityRank ent_type, EntityId ent_id) const
00199 {
00200   m_mesh_meta_data.assert_entity_rank( calling_method , ent_type );
00201 
00202   if (!entity_id_valid(ent_id)) {
00203     std::ostringstream msg;
00204     msg << calling_method << ": ent_id not valid";
00205     std::string str = msg.str();
00206     throw std::runtime_error(str);
00207   }
00208 }
00209 
00210 //----------------------------------------------------------------------
00211 //----------------------------------------------------------------------
00212 // The add_parts must be full ordered and consistent,
00213 // i.e. no bad parts, all supersets included, and
00214 // owner & used parts match the owner value.
00215 
00216 
00217 
00218 //----------------------------------------------------------------------
00219 
00220 Entity & BulkData::declare_entity( EntityRank ent_type , EntityId ent_id ,
00221            const std::vector<Part*> & parts )
00222 {
00223   static const char method[] = "stk::mesh::BulkData::declare_entity" ;
00224 
00225   assert_ok_to_modify( method );
00226 
00227   verify_type_and_id("BulkData::declare_entity", ent_type, ent_id);
00228 
00229   EntityKey key( ent_type , ent_id );
00230 
00231   assert_good_key( method , key );
00232 
00233   std::pair< Entity * , bool > result = m_entity_repo.internal_create_entity( key );
00234 
00235   if ( result.second ) {
00236     // A new application-created entity
00237     m_entity_repo.set_entity_owner_rank( *(result.first), m_parallel_rank);
00238     m_entity_repo.set_entity_sync_count( *(result.first), m_sync_count);
00239   }
00240   else {
00241     // An existing entity, the owner must match.
00242     assert_entity_owner( method , * result.first , m_parallel_rank );
00243   }
00244 
00245   //------------------------------
00246 
00247   Part * const owns = & m_mesh_meta_data.locally_owned_part();
00248 
00249   std::vector<Part*> rem ;
00250   std::vector<Part*> add( parts );
00251   add.push_back( owns );
00252 
00253   change_entity_parts( * result.first , add , rem );
00254 
00255   // m_transaction_log.insert_entity ( *(result.first) );
00256 
00257   return * result.first ;
00258 }
00259 
00260 //----------------------------------------------------------------------
00261 
00262 namespace {
00263 
00264 // Do not allow any of the induced part memberships to explicitly
00265 // appear in the add or remove parts lists.
00266 // 1) Intersection part
00267 // 2) PartRelation target part
00268 // 3) Part that does not match the entity type.
00269 
00270 void verify_change_parts( const char * method ,
00271                           const MetaData   & meta ,
00272                           const Entity     & entity ,
00273                           const PartVector & parts )
00274 {
00275   const std::vector<std::string> & type_names = meta.entity_rank_names();
00276   const unsigned undef_rank  = std::numeric_limits<unsigned>::max();
00277   const unsigned entity_rank = entity.entity_rank();
00278 
00279   bool ok = true ;
00280   std::ostringstream msg ;
00281 
00282   for ( PartVector::const_iterator
00283         i = parts.begin() ; i != parts.end() ; ++i ) {
00284 
00285     const Part * const p = *i ;
00286     const unsigned part_rank = p->primary_entity_rank();
00287 
00288     const bool error_intersection = ! p->intersection_of().empty();
00289     const bool error_rel_target   = ! p->relations().empty() &&
00290                                     p == p->relations().begin()->m_target ;
00291     const bool error_rank = entity_rank != part_rank &&
00292                             undef_rank  != part_rank ;
00293 
00294     if ( error_intersection || error_rel_target || error_rank ) {
00295       if ( ok ) {
00296         ok = false ;
00297         msg << method ;
00298         msg << "( " ;
00299         print_entity_key( msg , meta , entity.key() );
00300         msg << " , { " ;
00301       }
00302       else {
00303         msg << " , " ;
00304       }
00305 
00306       msg << p->name() << "[" ;
00307       if ( part_rank < type_names.size() ) {
00308         msg << type_names[ part_rank ];
00309       }
00310       else {
00311         msg << part_rank ;
00312       }
00313       msg << "] " ;
00314       if ( error_intersection ) { msg << "is_intersection " ; }
00315       if ( error_rel_target )   { msg << "is_relation_target " ; }
00316       if ( error_rank )         { msg << "is_bad_rank " ; }
00317     }
00318   }
00319 
00320   if ( ! ok ) {
00321     msg << " }" ;
00322     throw std::runtime_error( msg.str() );
00323   }
00324 }
00325 
00326 }
00327 
00328 void BulkData::change_entity_parts(
00329   Entity & e ,
00330   const std::vector<Part*> & add_parts ,
00331   const std::vector<Part*> & remove_parts )
00332 {
00333   static const char method[] = "stk::mesh::BulkData::change_entity_parts" ;
00334 
00335   assert_ok_to_modify( method );
00336 
00337   assert_entity_owner( method , e , m_parallel_rank );
00338 
00339   // Transitive addition and removal:
00340   // 1) Include supersets of add_parts
00341   // 2) Do not include a remove_part if it appears in the add_parts
00342   // 3) Include subsets of remove_parts
00343 
00344   PartVector a_parts( add_parts );
00345 
00346   for ( PartVector::const_iterator
00347         ia = add_parts.begin(); ia != add_parts.end() ; ++ia ) {
00348     a_parts.insert( a_parts.end(), (*ia)->supersets().begin(),
00349                                    (*ia)->supersets().end() );
00350   }
00351 
00352   order( a_parts );
00353 
00354   PartVector r_parts ;
00355 
00356   for ( PartVector::const_iterator
00357         ir = remove_parts.begin(); ir != remove_parts.end() ; ++ir ) {
00358 
00359     // The following guards should be in the public interface to
00360     // changing parts.  However, internal mechanisms such as changing
00361     // ownership calls this function to add or remove an entity from
00362     // the three special parts.  Without refactoring, these guards
00363     // cannot be put in place.
00364     /*
00365     if ( m_mesh_meta_data.universal_part() == **ir )
00366       throw std::runtime_error ( "Cannot remove entity from universal part" );
00367     if ( m_mesh_meta_data.locally_owned_part() == **ir )
00368       throw std::runtime_error ( "Cannot remove entity from locally owned part" );
00369     if ( m_mesh_meta_data.globally_shared_part() == **ir )
00370       throw std::runtime_error ( "Cannot remove entity from globally shared part" );
00371     */
00372 
00373     if ( ! contain( a_parts , **ir ) ) {
00374       r_parts.push_back( *ir );
00375       for ( PartVector::const_iterator  cur_part = (*ir)->subsets().begin() ;
00376             cur_part != (*ir)->subsets().end() ;
00377             ++cur_part )
00378         if ( e.bucket().member ( **cur_part ) )
00379           r_parts.push_back ( *cur_part );
00380     }
00381   }
00382 
00383   order( r_parts );
00384 
00385   verify_change_parts( method , m_mesh_meta_data , e , a_parts );
00386   verify_change_parts( method , m_mesh_meta_data , e , r_parts );
00387 
00388   internal_change_entity_parts( e , a_parts , r_parts );
00389 
00390   return ;
00391 }
00392 
00393 //----------------------------------------------------------------------
00394 
00395 namespace {
00396 
00397 void filter_out( std::vector<unsigned> & vec ,
00398                  const PartVector & parts ,
00399                  PartVector & removed )
00400 {
00401   std::vector<unsigned>::iterator i , j ;
00402   i = j = vec.begin();
00403 
00404   PartVector::const_iterator ip = parts.begin() ;
00405 
00406   while ( j != vec.end() && ip != parts.end() ) {
00407     Part * const p = *ip ;
00408     if      ( p->mesh_meta_data_ordinal() < *j ) { ++ip ; }
00409     else if ( *j < p->mesh_meta_data_ordinal() ) { *i = *j ; ++i ; ++j ; }
00410     else {
00411       removed.push_back( p );
00412       ++j ;
00413       ++ip ;
00414     }
00415   }
00416 
00417   if ( i != j ) { vec.erase( i , j ); }
00418 }
00419 
00420 void merge_in( std::vector<unsigned> & vec , const PartVector & parts )
00421 {
00422   std::vector<unsigned>::iterator i = vec.begin();
00423   PartVector::const_iterator ip = parts.begin() ;
00424 
00425   for ( ; i != vec.end() && ip != parts.end() ; ++i ) {
00426 
00427     const unsigned ord = (*ip)->mesh_meta_data_ordinal();
00428 
00429     if ( ord <= *i ) {
00430       if ( ord < *i ) { i = vec.insert( i , ord ); }
00431       // Now have: ord == *i
00432       ++ip ;
00433     }
00434   }
00435 
00436   for ( ; ip != parts.end() ; ++ip ) {
00437     const unsigned ord = (*ip)->mesh_meta_data_ordinal();
00438     vec.push_back( ord );
00439   }
00440 }
00441 
00442 }
00443 
00444 //  The 'add_parts' and 'remove_parts' are complete and disjoint.
00445 //  Changes need to have parallel resolution during
00446 //  modification_end.
00447 
00448 void BulkData::internal_change_entity_parts(
00449   Entity & e ,
00450   const PartVector & add_parts ,
00451   const PartVector & remove_parts )
00452 {
00453   Bucket * const k_old = m_entity_repo.get_entity_bucket( e );
00454 
00455   const unsigned i_old = e.bucket_ordinal() ;
00456 
00457   if ( k_old && k_old->member_all( add_parts ) &&
00458               ! k_old->member_any( remove_parts ) ) {
00459     // Is already a member of all add_parts,
00460     // is not a member of any remove_parts,
00461     // thus nothing to do.
00462     return ;
00463   }
00464 
00465   PartVector parts_removed ;
00466 
00467   std::vector<unsigned> parts_total ; // The final part list
00468 
00469   //--------------------------------
00470 
00471   if ( k_old ) {
00472     // Keep any of the existing bucket's parts
00473     // that are not a remove part.
00474     // This will include the 'intersection' parts.
00475     //
00476     // These parts are properly ordered and unique.
00477 
00478     const std::pair<const unsigned *, const unsigned*>
00479       bucket_parts = k_old->superset_part_ordinals();
00480 
00481     parts_total.assign( bucket_parts.first , bucket_parts.second );
00482 
00483     filter_out( parts_total , remove_parts , parts_removed );
00484   }
00485 
00486   merge_in( parts_total , add_parts );
00487 
00488   if ( parts_total.empty() ) {
00489     // Always a member of the universal part.
00490     const unsigned univ_ord =
00491       m_mesh_meta_data.universal_part().mesh_meta_data_ordinal();
00492     parts_total.push_back( univ_ord );
00493   }
00494 
00495   //--------------------------------
00496   // Move the entity to the new bucket.
00497 
00498   Bucket * k_new =
00499     m_bucket_repository.declare_bucket(
00500         e.entity_rank(),
00501         parts_total.size(),
00502         & parts_total[0] ,
00503         m_mesh_meta_data.get_fields()
00504         );
00505 
00506   // If changing buckets then copy its field values from old to new bucket
00507 
00508   if ( k_old ) {
00509     m_bucket_repository.copy_fields( *k_new , k_new->size() , *k_old , i_old );
00510   }
00511   else {
00512     m_bucket_repository.zero_fields( *k_new , k_new->size() );
00513   }
00514 
00515   // Set the new bucket
00516   m_entity_repo.change_entity_bucket( *k_new, e, k_new->size() );
00517   m_bucket_repository.add_entity_to_bucket( e, *k_new );
00518 
00519   // If changing buckets then remove the entity from the bucket,
00520   if ( k_old ) { m_bucket_repository.remove_entity( k_old , i_old ); }
00521 
00522   // Update the change counter to the current cycle.
00523   m_entity_repo.set_entity_sync_count( e, m_sync_count );
00524 
00525   // Propagate part changes through the entity's relations.
00526 
00527   internal_propagate_part_changes( e , parts_removed );
00528 }
00529 
00530 //----------------------------------------------------------------------
00531 
00532 bool BulkData::destroy_entity( Entity * & e )
00533 {
00534   static const char method[] = "stk::mesh::BulkData::destroy_entity" ;
00535 
00536   Entity & entity = *e ;
00537 
00538   assert_ok_to_modify( method );
00539 
00540   bool has_upward_relation = false ;
00541 
00542   for ( PairIterRelation
00543         irel = entity.relations() ;
00544         ! irel.empty() && ! has_upward_relation ; ++irel ) {
00545 
00546     has_upward_relation = entity.entity_rank() <= irel->entity_rank();
00547   }
00548 
00549   if ( has_upward_relation ) { return false ; }
00550 
00551   if (  EntityLogDeleted == entity.log_query() ) {
00552     // Cannot already be destroyed.
00553     return false ;
00554   }
00555   //------------------------------
00556   // Immediately remove it from relations and buckets.
00557   // Postpone deletion until modification_end to be sure that
00558   // 1) No attempt is made to re-create it.
00559   // 2) Parallel index is cleaned up.
00560   // 3) Parallel sharing is cleaned up.
00561   // 4) Parallel ghosting is cleaned up.
00562   //
00563   // Must clean up the parallel lists before fully deleting the entity.
00564 
00565   while ( ! entity.relations().empty() ) {
00566     destroy_relation( entity , * entity.relations().back().entity() );
00567   }
00568 
00569   // We need to save these items and call remove_entity AFTER the call to
00570   // destroy_later because remove_entity may destroy the bucket
00571   // which would cause problems in m_entity_repo.destroy_later because it
00572   // makes references to the entity's original bucket.
00573   Bucket& orig_bucket = entity.bucket();
00574   unsigned orig_bucket_ordinal = entity.bucket_ordinal();
00575 
00576   // Set the bucket to 'bucket_nil' which:
00577   //   1) has no parts at all
00578   //   2) has no field data
00579   //   3) has zero capacity
00580   //
00581   // This keeps the entity-bucket methods from catastrophically failing
00582   // with a bad bucket pointer.
00583 
00584   m_entity_repo.destroy_later( entity, m_bucket_repository.get_nil_bucket() );
00585 
00586   m_bucket_repository.remove_entity( &orig_bucket , orig_bucket_ordinal );
00587 
00588   // Add destroyed entity to the transaction
00589   // m_transaction_log.delete_entity ( *e );
00590 
00591   // Set the calling entity-pointer to NULL;
00592   // hopefully the user-code will clean up any outstanding
00593   // references to this entity.
00594 
00595   e = NULL ;
00596 
00597   return true ;
00598 }
00599 
00600 //----------------------------------------------------------------------
00601 
00602 void BulkData::generate_new_entities(const std::vector<size_t>& requests,
00603                                  std::vector<Entity *>& requested_entities)
00604 {
00605   typedef stk::parallel::DistributedIndex::KeyType KeyType;
00606   std::vector< std::vector<KeyType> >
00607     requested_key_types;
00608   m_entities_index.generate_new_keys(requests, requested_key_types);
00609 
00610   //generating 'owned' entities
00611   Part * const owns = & m_mesh_meta_data.locally_owned_part();
00612 
00613   std::vector<Part*> rem ;
00614   std::vector<Part*> add;
00615   add.push_back( owns );
00616 
00617   requested_entities.clear();
00618   for (std::vector< std::vector<KeyType> >::const_iterator itr = requested_key_types.begin(); itr != requested_key_types.end(); ++itr) {
00619     const std::vector<KeyType>& key_types = *itr;
00620     for (std::vector<KeyType>::const_iterator
00621         kitr = key_types.begin(); kitr != key_types.end(); ++kitr) {
00622       EntityKey key(&(*kitr));
00623       std::pair<Entity *, bool> result = m_entity_repo.internal_create_entity(key);
00624 
00625       if ( result.second ) {
00626         // A new application-created entity
00627         m_entity_repo.set_entity_owner_rank( *(result.first), m_parallel_rank);
00628         m_entity_repo.set_entity_sync_count( *(result.first), m_sync_count);
00629       }
00630       else {
00631         //if an entity is declare with the declare_entity function in the same
00632         //modification cycle as the generate_new_entities function, and it happens to
00633         //generate a key that was declare previously in the same cycle it is an error
00634         std::ostringstream msg;
00635         msg << "stk::mesh::BulkData::generate_new_entities ERROR:";
00636         msg << " generated ";
00637         print_entity_key(msg, m_mesh_meta_data, key);
00638         msg << " which was already used in this modification cycle.";
00639         throw std::runtime_error(msg.str());
00640       }
00641       //add entity to 'owned' part
00642       change_entity_parts( * result.first , add , rem );
00643       requested_entities.push_back(result.first);
00644     }
00645   }
00646 }
00647 
00648 
00649 //----------------------------------------------------------------------
00650 //----------------------------------------------------------------------
00651 
00652 } // namespace mesh
00653 } // namespace stk
00654 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends