|
Sierra Toolkit Version of the Day
|
00001 /*------------------------------------------------------------------------*/ 00002 /* Copyright 2010 Sandia Corporation. */ 00003 /* Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive */ 00004 /* license for use of this work by or on behalf of the U.S. Government. */ 00005 /* Export of this program may require a license from the */ 00006 /* United States Government. */ 00007 /*------------------------------------------------------------------------*/ 00008 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