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