|
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 <set> 00017 #include <vector> 00018 #include <algorithm> 00019 00020 #include <stk_util/parallel/ParallelComm.hpp> 00021 #include <stk_util/parallel/ParallelReduce.hpp> 00022 00023 #include <stk_mesh/base/BulkData.hpp> 00024 #include <stk_mesh/base/MetaData.hpp> 00025 #include <stk_mesh/base/Entity.hpp> 00026 #include <stk_mesh/base/EntityComm.hpp> 00027 #include <stk_mesh/base/Bucket.hpp> 00028 00029 namespace stk { 00030 namespace mesh { 00031 00032 //---------------------------------------------------------------------- 00033 00034 namespace { 00035 00036 void insert_closure_ghost( Entity * const entity , 00037 const unsigned proc_local , 00038 std::set<Entity*,EntityLess> & remove_list ) 00039 { 00040 if ( ! in_owned_closure( *entity , proc_local ) ) { 00041 // This entity is a ghost, put it on the remove_list 00042 // along with all ghosts in its closure 00043 00044 std::pair< std::set<Entity*,EntityLess>::iterator , bool > 00045 result = remove_list.insert( entity ); 00046 00047 if ( result.second ) { 00048 // This ghost entity is new to the list, traverse its closure. 00049 00050 const unsigned etype = entity->entity_rank(); 00051 00052 for ( PairIterRelation 00053 irel = entity->relations() ; ! irel.empty() ; ++irel ) { 00054 00055 if ( irel->entity_rank() < etype ) { 00056 insert_closure_ghost( irel->entity() , proc_local ,remove_list ); 00057 } 00058 } 00059 } 00060 } 00061 } 00062 00063 void insert_transitive_ghost( Entity * const entity , 00064 const unsigned proc_local , 00065 std::set<Entity*,EntityLess> & remove_list ) 00066 { 00067 insert_closure_ghost( entity , proc_local , remove_list ); 00068 00069 // Transitive: 00070 // If this entity is a member of another entity's closure 00071 // then that other entity is part of the traversal. 00072 00073 const unsigned etype = entity->entity_rank(); 00074 00075 for ( PairIterRelation rel = entity->relations(); ! rel.empty() ; ++rel ) { 00076 if ( etype < rel->entity_rank() ) { 00077 insert_transitive_ghost( rel->entity() , proc_local , remove_list ); 00078 } 00079 } 00080 } 00081 00082 //---------------------------------------------------------------------- 00083 00084 void insert_closure_send( 00085 const EntityProc send_entry , 00086 std::set<EntityProc,EntityLess> & send_list ) 00087 { 00088 if ( EntityLogDeleted == send_entry.first->log_query() ) { 00089 throw std::logic_error( std::string("Cannot send destroyed entity") ); 00090 } 00091 00092 std::pair< std::set<EntityProc,EntityLess>::iterator , bool > 00093 result = send_list.insert( send_entry ); 00094 00095 if ( result.second ) { 00096 // First time this entity was inserted into the send_list. 00097 00098 const unsigned erank = send_entry.first->entity_rank(); 00099 PairIterRelation irel = send_entry.first->relations(); 00100 00101 for ( ; ! irel.empty() ; ++irel ) { 00102 if ( irel->entity_rank() < erank ) { 00103 const EntityProc rel_send_entry( irel->entity(), send_entry.second ); 00104 00105 insert_closure_send( rel_send_entry , send_list ); 00106 } 00107 } 00108 } 00109 } 00110 00111 //---------------------------------------------------------------------- 00112 00113 bool member_of_owned_closure( const Entity & e , const unsigned p_rank ) 00114 { 00115 bool result = p_rank == e.owner_rank(); 00116 00117 const unsigned etype = e.entity_rank(); 00118 00119 // Any higher ranking entities locally owned? 00120 for ( PairIterRelation 00121 irel = e.relations(); ! result && ! irel.empty() ; ++irel ) { 00122 result = etype < irel->entity_rank() && 00123 p_rank == irel->entity()->owner_rank(); 00124 } 00125 00126 // Any higher ranking entity member of an owned closure? 00127 for ( PairIterRelation 00128 irel = e.relations(); ! result && ! irel.empty() ; ++irel ) { 00129 result = etype < irel->entity_rank() && 00130 member_of_owned_closure( * irel->entity() , p_rank ); 00131 } 00132 00133 return result ; 00134 } 00135 00136 //---------------------------------------------------------------------- 00137 00138 void clean_and_verify_parallel_change( 00139 const char method[] , 00140 const BulkData & mesh , 00141 std::vector<EntityProc> & local_change ) 00142 { 00143 const MetaData & meta = mesh.mesh_meta_data() ; 00144 const unsigned p_rank = mesh.parallel_rank(); 00145 const unsigned p_size = mesh.parallel_size(); 00146 const ParallelMachine p_comm = mesh.parallel(); 00147 00148 size_t error_count = 0 ; 00149 00150 std::ostringstream error_msg ; 00151 00152 // Order and eliminate redundancies: 00153 { 00154 std::vector<EntityProc>::iterator i = local_change.begin() , 00155 j = local_change.end() ; 00156 std::sort( i , j , EntityLess() ); 00157 i = std::unique( i , j ); 00158 local_change.erase( i , j ); 00159 } 00160 00161 for ( std::vector<EntityProc>::iterator 00162 i = local_change.begin() ; i != local_change.end() ; ) { 00163 std::vector<EntityProc>::iterator j = i ; ++i ; 00164 Entity * const entity = j->first ; 00165 const unsigned new_owner = j->second ; 00166 00167 // Verification: 00168 // 1) If bucket has no capacity then is destined for deletion 00169 // 2) If not locally owned then not allowed grant ownership 00170 // 3) New owner must be legit 00171 // 4) Cannot grant to two different owners 00172 00173 const bool bad_null = NULL == entity ; 00174 const bool bad_delete = ! bad_null && EntityLogDeleted == entity->log_query(); 00175 const bool bad_entity = ! bad_null && entity->owner_rank() != p_rank ; 00176 const bool bad_owner = p_size <= new_owner ; 00177 const bool bad_dup = ! bad_null && i != local_change.end() && entity == i->first ; 00178 00179 if ( bad_null || bad_entity || bad_owner || bad_dup || bad_delete ) { 00180 ++error_count ; 00181 00182 error_msg << " P" << p_rank << ": " ; 00183 if ( bad_null ) { error_msg << " NULL ENTITY" ; } 00184 else { print_entity_key( error_msg , meta , entity->key() ); } 00185 if ( bad_delete ) { error_msg << " HAS_BEEN_DELETED" ; } 00186 if ( bad_entity ) { error_msg << " NOT_CURRENT_OWNER" ; } 00187 if ( bad_owner ) { 00188 error_msg << " BAD_NEW_OWNER( " << new_owner << " )" ; 00189 } 00190 if ( bad_dup ) { 00191 error_msg << " CONFLICTING_NEW_OWNER( " << new_owner ; 00192 error_msg << " != " << i->second << " )" ; 00193 } 00194 error_msg << std::endl ; 00195 } 00196 else if ( new_owner == p_rank ) { 00197 // Eliminate non-changes 00198 j->first = NULL ; 00199 j->second = 0 ; 00200 } 00201 } 00202 00203 all_reduce( p_comm , ReduceSum<1>( & error_count ) ); 00204 00205 if ( error_count ) { 00206 std::string msg_throw ; 00207 msg_throw.append( method ); 00208 msg_throw.append( " FAILED: Bad change ownership directives" ); 00209 00210 if ( 0 == p_rank ) { std::cerr << msg_throw ; } 00211 00212 all_write_string( p_comm , std::cerr , error_msg.str() ); 00213 00214 throw std::runtime_error( msg_throw ); 00215 } 00216 00217 { 00218 std::vector<EntityProc>::iterator i = local_change.begin(), 00219 j = local_change.end(); 00220 i = std::remove( i , j , EntityProc(NULL,0) ); 00221 local_change.erase( i , j ); 00222 } 00223 } 00224 00225 //---------------------------------------------------------------------- 00226 // Generate a parallel consistent list of ownership changes: 00227 // 1) Shared entities (not owned but in closure of an owned entity), 00228 // 2) Ghosted entities (not owned and not in closure of an owned entity), and 00229 // 3) Parallel index. 00230 00231 void generate_parallel_change( const BulkData & mesh , 00232 const std::vector<EntityProc> & local_change , 00233 std::vector<EntityProc> & shared_change , 00234 std::vector<EntityProc> & ghosted_change ) 00235 { 00236 const unsigned p_size = mesh.parallel_size(); 00237 00238 CommAll comm( mesh.parallel() ); 00239 00240 // Sizing: 00241 00242 std::vector<unsigned> procs ; 00243 00244 for ( std::vector<EntityProc>::const_iterator 00245 ip = local_change.begin() ; ip != local_change.end() ; ++ip ) { 00246 Entity & entity = * ip->first ; 00247 comm_procs( entity , procs ); 00248 for ( std::vector<unsigned>::iterator 00249 j = procs.begin() ; j != procs.end() ; ++j ) { 00250 comm.send_buffer( *j ).skip<EntityKey>(1).skip<unsigned>(1); 00251 } 00252 } 00253 00254 // Allocation: 00255 00256 comm.allocate_buffers( p_size / 4 , 0 ); 00257 00258 // Packing new owner info: 00259 00260 for ( std::vector<EntityProc>::const_iterator 00261 ip = local_change.begin() ; ip != local_change.end() ; ++ip ) { 00262 Entity & entity = * ip->first ; 00263 comm_procs( entity , procs ); 00264 for ( std::vector<unsigned>::iterator 00265 j = procs.begin() ; j != procs.end() ; ++j ) { 00266 comm.send_buffer( *j ) 00267 .pack<EntityKey>( entity.key() ) 00268 .pack<unsigned>( ip->second ); 00269 } 00270 } 00271 00272 comm.communicate(); 00273 00274 for ( unsigned ip = 0 ; ip < p_size ; ++ip ) { 00275 CommBuffer & buf = comm.recv_buffer( ip ); 00276 while ( buf.remaining() ) { 00277 EntityProc entry ; 00278 EntityKey key ; 00279 buf.unpack<EntityKey>( key ) 00280 .unpack<unsigned>( entry.second ); 00281 00282 entry.first = mesh.get_entity( key ); 00283 00284 if ( in_receive_ghost( * entry.first ) ) { 00285 ghosted_change.push_back( entry ); 00286 } 00287 else { 00288 shared_change.push_back( entry ); 00289 } 00290 } 00291 } 00292 00293 std::sort( shared_change.begin() , shared_change.end() , EntityLess() ); 00294 std::sort( ghosted_change.begin() , ghosted_change.end() , EntityLess() ); 00295 } 00296 00297 } 00298 00299 //---------------------------------------------------------------------- 00300 //---------------------------------------------------------------------- 00301 00302 void BulkData::change_entity_owner( const std::vector<EntityProc> & arg_change ) 00303 { 00304 static const char method[] = "stk::mesh::BulkData::change_entity_owner" ; 00305 00306 const MetaData & meta = m_mesh_meta_data ; 00307 const unsigned p_rank = m_parallel_rank ; 00308 const unsigned p_size = m_parallel_size ; 00309 ParallelMachine p_comm = m_parallel_machine ; 00310 00311 //------------------------------ 00312 // Verify the input changes, generate a clean local change list, and 00313 // generate the remote change list so that all processes know about 00314 // pending changes. 00315 00316 std::vector<EntityProc> local_change( arg_change ); 00317 00318 // Parallel synchronous clean up and verify the requested changes: 00319 clean_and_verify_parallel_change( method , *this , local_change ); 00320 00321 //---------------------------------------- 00322 // Parallel synchronous determination of changing 00323 // shared and ghosted. 00324 00325 std::vector<EntityProc> ghosted_change ; 00326 std::vector<EntityProc> shared_change ; 00327 00328 generate_parallel_change( *this , local_change , 00329 shared_change , ghosted_change ); 00330 00331 //------------------------------ 00332 // Have enough information to delete all effected ghosts. 00333 // If the closure of a ghost contains a changing entity 00334 // then that ghost must be deleted. 00335 // Request that all ghost entities in the closure of the ghost be deleted. 00336 00337 typedef std::set<EntityProc,EntityLess> EntityProcSet; 00338 typedef std::set<Entity*,EntityLess> EntitySet; 00339 00340 // Closure of the owner change for impacted ghost entities. 00341 00342 EntityProcSet send_closure ; 00343 00344 for ( std::vector<EntityProc>::iterator 00345 i = local_change.begin() ; i != local_change.end() ; ++i ) { 00346 insert_closure_send( *i , send_closure ); 00347 } 00348 00349 { 00350 EntitySet work ; 00351 00352 for ( std::vector<EntityProc>::const_iterator 00353 i = ghosted_change.begin() ; i != ghosted_change.end() ; ++i ) { 00354 insert_transitive_ghost( i->first , m_parallel_rank , work ); 00355 } 00356 00357 for ( std::vector<EntityProc>::const_iterator 00358 i = shared_change.begin() ; i != shared_change.end() ; ++i ) { 00359 insert_transitive_ghost( i->first , m_parallel_rank , work ); 00360 } 00361 00362 for ( EntityProcSet::iterator 00363 i = send_closure.begin() ; i != send_closure.end() ; ++i ) { 00364 insert_transitive_ghost( i->first , m_parallel_rank , work ); 00365 } 00366 00367 // The ghosted change list will become invalid 00368 ghosted_change.clear(); 00369 00370 std::vector<EntityProc> empty ; 00371 std::vector<Entity*> effected_ghosts( work.begin() , work.end() ); 00372 00373 // Skip 'm_ghosting[0]' which is the shared subset. 00374 for ( std::vector<Ghosting*>::iterator 00375 ig = m_ghosting.begin() + 1 ; ig != m_ghosting.end() ; ++ig ) { 00376 // parallel synchronous: 00377 internal_change_ghosting( **ig , empty , effected_ghosts ); 00378 } 00379 } 00380 00381 //------------------------------ 00382 // Consistently change the owner on all processes. 00383 // 1) The local_change list is giving away ownership. 00384 // 2) The shared_change may or may not be receiving ownership 00385 00386 { 00387 PartVector owned( 1 ); 00388 owned[0] = & meta.locally_owned_part(); 00389 00390 for ( std::vector<EntityProc>::iterator 00391 i = local_change.begin() ; i != local_change.end() ; ++i ) { 00392 // Giving ownership, change the parts first and then 00393 // the owner rank to pass the ownership test. 00394 change_entity_parts( * i->first , PartVector() , owned ); 00395 00396 m_entity_repo.set_entity_owner_rank( *(i->first), i->second); 00397 } 00398 00399 for ( std::vector<EntityProc>::iterator 00400 i = shared_change.begin() ; i != shared_change.end() ; ++i ) { 00401 m_entity_repo.set_entity_owner_rank( *(i->first), i->second); 00402 if ( p_rank == i->second ) { // I receive ownership 00403 change_entity_parts( * i->first , owned , PartVector() ); 00404 } 00405 } 00406 } 00407 00408 //------------------------------ 00409 // Send entities, along with their closure, to the new owner processes 00410 { 00411 std::ostringstream error_msg ; 00412 int error_count = 0 ; 00413 00414 CommAll comm( p_comm ); 00415 00416 for ( std::set<EntityProc,EntityLess>::iterator 00417 i = send_closure.begin() ; i != send_closure.end() ; ++i ) { 00418 CommBuffer & buffer = comm.send_buffer( i->second ); 00419 Entity & entity = * i->first ; 00420 pack_entity_info( buffer , entity ); 00421 pack_field_values( buffer , entity ); 00422 } 00423 00424 comm.allocate_buffers( p_size / 4 ); 00425 00426 for ( std::set<EntityProc,EntityLess>::iterator 00427 i = send_closure.begin() ; i != send_closure.end() ; ++i ) { 00428 CommBuffer & buffer = comm.send_buffer( i->second ); 00429 Entity & entity = * i->first ; 00430 pack_entity_info( buffer , entity ); 00431 pack_field_values( buffer , entity ); 00432 } 00433 00434 comm.communicate(); 00435 00436 for ( unsigned p = 0 ; p < p_size ; ++p ) { 00437 CommBuffer & buf = comm.recv_buffer(p); 00438 while ( buf.remaining() ) { 00439 PartVector parts ; 00440 std::vector<Relation> relations ; 00441 EntityKey key ; 00442 unsigned owner = ~0u ; 00443 00444 unpack_entity_info( buf, *this, key, owner, parts, relations ); 00445 00446 // Received entity information will be correct, 00447 // modulo the owned and shared parts 00448 00449 remove( parts , meta.globally_shared_part() ); 00450 00451 if ( owner == p_rank ) { 00452 // Must have the locally_owned_part 00453 insert( parts , meta.locally_owned_part() ); 00454 } 00455 else { 00456 // Must not have the locally_owned_part 00457 remove( parts , meta.locally_owned_part() ); 00458 } 00459 00460 std::pair<Entity*,bool> result = 00461 m_entity_repo.internal_create_entity( key ); 00462 00463 m_entity_repo.log_created_parallel_copy( *(result.first) ); 00464 00465 // The entity was copied and not created. 00466 00467 m_entity_repo.set_entity_owner_rank( *(result.first), owner); 00468 00469 internal_change_entity_parts( *result.first , parts , PartVector() ); 00470 00471 declare_relation( *result.first , relations ); 00472 00473 if ( ! unpack_field_values( buf , * result.first , error_msg ) ) { 00474 ++error_count ; 00475 } 00476 } 00477 } 00478 00479 all_reduce( p_comm , ReduceSum<1>( & error_count ) ); 00480 00481 if ( error_count ) { throw std::runtime_error( error_msg.str() ); } 00482 00483 // Any entity that I sent and is not in an owned closure is deleted. 00484 // The owned closure will be effected by received entities, so can 00485 // only clean up after the newly owned entities have been received. 00486 // Destroy backwards so as not to invalidate closures in the process. 00487 00488 { 00489 Entity * entity = NULL ; 00490 00491 for ( std::set<EntityProc,EntityLess>::iterator 00492 i = send_closure.end() ; i != send_closure.begin() ; ) { 00493 00494 Entity * e = (--i)->first ; 00495 00496 // The same entity may be sent to more than one process. 00497 // Only evaluate it once. 00498 00499 if ( entity != e ) { 00500 entity = e ; 00501 if ( ! member_of_owned_closure( *e , p_rank ) ) { 00502 if ( ! destroy_entity( e ) ) { 00503 throw std::logic_error(std::string("BulkData::destroy_entity FAILED")); 00504 } 00505 } 00506 } 00507 } 00508 } 00509 00510 send_closure.clear(); // Has been invalidated 00511 } 00512 } 00513 00514 //---------------------------------------------------------------------- 00515 00516 } // namespace mesh 00517 } // namespace stk 00518