void BulkData::destroy_relation( Entity & e1 , Entity & e2 , unsigned kind ) { // When removing a relationship may need to // remove part membership and set field relation pointer to NULL PartSet del ; bool to_e1 = false ; std::vector<Relation>::iterator i ; for ( i = e1.m_relation.end() ; i != e1.m_relation.begin() ; ) { --i ; if ( i->entity() == & e2 && i->kind() == kind ) { if ( i->forward() ) { clear_field_relations( e1 , i->entity_type() , i->identifier() , i->kind() ); deduce_part_relations( e1, e2, i->identifier(), i->kind(), del ); } i = e1.m_relation.erase( i ); } } for ( i = e2.m_relation.end() ; i != e2.m_relation.begin() ; ) { --i ; if ( i->entity() == & e1 && i->kind() == kind ) { if ( i->forward() ) { clear_field_relations( e2 , i->entity_type() , i->identifier() , i->kind() ); deduce_part_relations( e2, e1, i->identifier(), i->kind(), del ); to_e1 = true ; } i = e2.m_relation.erase( i ); } } Entity & e_to = to_e1 ? e1 : e2 ; { PartSet keep ; deduce_part_relations( e_to , keep ); if ( ! keep.empty() ) { // Eliminate the 'keep' from the accumulated 'del' for ( PartSet::iterator j = del.end() ; j != del.begin() ; ) { --j ; if ( contain( keep , **j ) ) { j = del.erase( j ); } } } } if ( ! del.empty() ) { PartSet add ; internal_change_entity_parts( e_to , add , del ); } }
void BulkData::declare_relation( Entity & e_from , Entity & e_to , const unsigned identifier , const unsigned kind ) { static const char method[] = "phdmesh::BulkData::declare_relation" ; if ( in_closure( e_to , e_from ) ) { std::ostringstream msg ; print_declare_relation( msg , method , e_from , e_to , identifier , kind ); msg << " FAILED DUE TO CIRCULAR CLOSURE." ; throw std::runtime_error( msg.str() ); } { const Relation forward( e_to , identifier , kind , false ); const std::vector<Relation>::iterator e = e_from.m_relation.end(); std::vector<Relation>::iterator i = e_from.m_relation.begin(); i = std::lower_bound( i , e , forward , LessRelation() ); if ( e == i || forward != *i ) { // Not a duplicate if ( e != i && forward.attribute() == i->attribute() ) { std::ostringstream msg ; print_declare_relation( msg, method, e_from, e_to, identifier, kind ); msg << " FAILED, ALREADY HAS THIS RELATION TO " ; print_entity_key( msg , i->entity()->key() ); throw std::runtime_error(msg.str()); } e_from.m_relation.insert( i , forward ); } } { const Relation converse( e_from , identifier , kind , true ); const std::vector<Relation>::iterator e = e_to.m_relation.end(); std::vector<Relation>::iterator i = e_to.m_relation.begin(); i = std::lower_bound( i , e , converse , LessRelation() ); if ( e == i || converse != *i ) { // Not a duplicate e_to.m_relation.insert( i , converse ); } } { PartSet add , del ; deduce_part_relations( e_from , e_to , identifier , kind , add ); internal_change_entity_parts( e_to , add , del ); } set_field_relations( e_from , e_to , identifier , kind ); }
void BulkData::destroy_relation( Entity & e_from , Entity & e_to ) { static const char method[]= "stk::mesh::BulkData::destroy_relation" ; assert_ok_to_modify( method ); assert_valid_relation( method , *this , e_from , e_to ); //------------------------------ // When removing a relationship may need to // remove part membership and set field relation pointer to NULL PartVector del , keep ; for ( PairIterRelation i = e_to.relations() ; i.first != i.second ; ++(i.first) ) { if ( !( i.first->entity() == & e_from ) && ( e_to.entity_rank() < i.first->entity_rank() ) ) { induced_part_membership( * i.first->entity(), del, e_to.entity_rank(), i.first->identifier(), keep ); } } for ( PairIterRelation i = e_from.relations() ; i.first != i.second ; ++(i.first) ) { if ( i.first->entity() == & e_to ) { induced_part_membership( e_from, keep, e_to.entity_rank(), i.first->identifier(), del ); clear_field_relations( e_from , e_to.entity_rank() , i.first->identifier() ); } } //------------------------------ // 'keep' contains the parts deduced from kept relations // 'del' contains the parts deduced from deleted relations // that are not in 'keep' // Only remove these part memberships the entity is not shared. // If the entity is shared then wait until modificaton_end_synchronize. //------------------------------ if ( ! del.empty() && (parallel_size() < 2 || e_to.sharing().empty()) ) { PartVector add ; internal_change_entity_parts( e_to , add , del ); } //delete relations from the entities m_entity_repo.destroy_relation( e_from, e_to); }
void BulkData::declare_relation( Entity & e_from , Entity & e_to , const unsigned local_id ) { static const char method[] = "stk::mesh::BulkData::declare_relation" ; assert_ok_to_modify( method ); assert_valid_relation( method , *this , e_from , e_to ); m_entity_repo.declare_relation( e_from, e_to, local_id, m_sync_count); PartVector add , empty ; // Deduce and set new part memberships: induced_part_membership( e_from, empty, e_to.entity_rank(), local_id, add ); internal_change_entity_parts( e_to , add , empty ); set_field_relations( e_from , e_to , local_id ); }
void BulkData::internal_propagate_part_changes( Entity & entity , const PartVector & removed ) { const unsigned etype = entity.entity_rank(); PairIterRelation rel = entity.relations(); for ( ; ! rel.empty() ; ++rel ) { const unsigned rel_type = rel->entity_rank(); const unsigned rel_ident = rel->identifier(); if ( rel_type < etype ) { // a 'to' entity Entity & e_to = * rel->entity(); PartVector to_del , to_add , empty ; // Induce part membership from this relationship to // pick up any additions. induced_part_membership( entity, empty, rel_type, rel_ident, to_add ); if ( ! removed.empty() ) { // Something was removed from the 'from' entity, // deduce what may have to be removed from the 'to' entity. // Deduce parts for 'e_to' from all upward relations. // Any non-parallel part that I removed that is not deduced for // 'e_to' must be removed from 'e_to' for ( PairIterRelation to_rel = e_to.relations(); ! to_rel.empty() ; ++to_rel ) { if ( e_to.entity_rank() < to_rel->entity_rank() && & entity != to_rel->entity() /* Already did this entity */ ) { // Relation from to_rel->entity() to e_to induced_part_membership( * to_rel->entity(), empty, e_to.entity_rank(), to_rel->identifier(), to_add ); } } for ( PartVector::const_iterator j = removed.begin() ; j != removed.end() ; ++j ) { if ( ! contain( to_add , **j ) ) { induced_part_membership( **j, etype, rel_type, rel_ident, to_del ); } } } if ( parallel_size() < 2 || e_to.sharing().empty() ) { // Entirely local, ok to remove memberships now internal_change_entity_parts( e_to , to_add , to_del ); } else { // Shared, do not remove memberships now. // Wait until modification_end. internal_change_entity_parts( e_to , to_add , empty ); } set_field_relations( entity, e_to, rel_ident ); } else if ( etype < rel_type ) { // a 'from' entity Entity & e_from = * rel->entity(); set_field_relations( e_from, entity, rel_ident ); } } }
void BulkData::internal_propagate_part_changes( Entity & entity , const PartSet & removed ) { const EntityType etype = entity.entity_type(); Part * const owns_part = & m_mesh_meta_data.locally_owned_part(); Part * const uses_part = & m_mesh_meta_data.locally_used_part(); PairIterRelation rel = entity.relations(); for ( ; rel ; ++rel ) { const unsigned rel_ident = rel->identifier(); const unsigned rel_kind = rel->kind(); if ( rel->forward() ) { Entity & e_to = * rel->entity(); PartSet to_del ; PartSet to_add ; if ( ! removed.empty() ) { const EntityType t_to = e_to.entity_type(); // Deduce parts for 'e_to' from all upward relations. // Any non-parallel part that I removed that is not deduced for // 'e_to' must be removed from 'e_to' deduce_part_relations( e_to , to_add ); to_del.reserve( removed.size() ); for ( PartSet::const_iterator j = removed.begin() ; j != removed.end() ; ++j ) { Part * const p = *j ; if ( p != owns_part && p != uses_part && ! contain( to_add , *p ) ) { to_del.push_back( p ); // What if removing a part with a part-relation ? const std::vector<PartRelation> & part_rel = m_mesh_meta_data.get_part_relations(); for ( std::vector<PartRelation>::const_iterator k = part_rel.begin() ; k != part_rel.end() ; ++k ) { const PartRelation & stencil = *k ; if ( p == stencil.m_root && 0 <= (*stencil.m_function)(etype,t_to,rel_ident,rel_kind) && ! contain( to_add , * stencil.m_target ) ) { } } } } } else { deduce_part_relations( entity , e_to , rel_ident , rel_kind , to_add ); } internal_change_entity_parts( e_to , to_add , to_del ); set_field_relations( entity, e_to, rel_ident , rel_kind ); } else { Entity & e_from = * rel->entity(); set_field_relations( e_from, entity, rel_ident, rel_kind ); } } }
void BulkData::change_entity_owner( const std::vector<EntityProc> & arg_change ) { static const char method[] = "stk::mesh::BulkData::change_entity_owner" ; const MetaData & meta = m_mesh_meta_data ; const unsigned p_rank = m_parallel_rank ; const unsigned p_size = m_parallel_size ; ParallelMachine p_comm = m_parallel_machine ; //------------------------------ // Verify the input changes, generate a clean local change list, and // generate the remote change list so that all processes know about // pending changes. std::vector<EntityProc> local_change( arg_change ); // Parallel synchronous clean up and verify the requested changes: clean_and_verify_parallel_change( method , *this , local_change ); //---------------------------------------- // Parallel synchronous determination of changing // shared and ghosted. std::vector<EntityProc> ghosted_change ; std::vector<EntityProc> shared_change ; generate_parallel_change( *this , local_change , shared_change , ghosted_change ); //------------------------------ // Have enough information to delete all effected ghosts. // If the closure of a ghost contains a changing entity // then that ghost must be deleted. // Request that all ghost entities in the closure of the ghost be deleted. typedef std::set<EntityProc,EntityLess> EntityProcSet; typedef std::set<Entity*,EntityLess> EntitySet; // Closure of the owner change for impacted ghost entities. EntityProcSet send_closure ; for ( std::vector<EntityProc>::iterator i = local_change.begin() ; i != local_change.end() ; ++i ) { insert_closure_send( *i , send_closure ); } { EntitySet work ; for ( std::vector<EntityProc>::const_iterator i = ghosted_change.begin() ; i != ghosted_change.end() ; ++i ) { insert_transitive_ghost( i->first , m_parallel_rank , work ); } for ( std::vector<EntityProc>::const_iterator i = shared_change.begin() ; i != shared_change.end() ; ++i ) { insert_transitive_ghost( i->first , m_parallel_rank , work ); } for ( EntityProcSet::iterator i = send_closure.begin() ; i != send_closure.end() ; ++i ) { insert_transitive_ghost( i->first , m_parallel_rank , work ); } // The ghosted change list will become invalid ghosted_change.clear(); std::vector<EntityProc> empty ; std::vector<Entity*> effected_ghosts( work.begin() , work.end() ); // Skip 'm_ghosting[0]' which is the shared subset. for ( std::vector<Ghosting*>::iterator ig = m_ghosting.begin() + 1 ; ig != m_ghosting.end() ; ++ig ) { // parallel synchronous: internal_change_ghosting( **ig , empty , effected_ghosts ); } } //------------------------------ // Consistently change the owner on all processes. // 1) The local_change list is giving away ownership. // 2) The shared_change may or may not be receiving ownership { PartVector owned( 1 ); owned[0] = & meta.locally_owned_part(); for ( std::vector<EntityProc>::iterator i = local_change.begin() ; i != local_change.end() ; ++i ) { // Giving ownership, change the parts first and then // the owner rank to pass the ownership test. change_entity_parts( * i->first , PartVector() , owned ); m_entity_repo.set_entity_owner_rank( *(i->first), i->second); } for ( std::vector<EntityProc>::iterator i = shared_change.begin() ; i != shared_change.end() ; ++i ) { m_entity_repo.set_entity_owner_rank( *(i->first), i->second); if ( p_rank == i->second ) { // I receive ownership change_entity_parts( * i->first , owned , PartVector() ); } } } //------------------------------ // Send entities, along with their closure, to the new owner processes { std::ostringstream error_msg ; int error_count = 0 ; CommAll comm( p_comm ); for ( std::set<EntityProc,EntityLess>::iterator i = send_closure.begin() ; i != send_closure.end() ; ++i ) { CommBuffer & buffer = comm.send_buffer( i->second ); Entity & entity = * i->first ; pack_entity_info( buffer , entity ); pack_field_values( buffer , entity ); } comm.allocate_buffers( p_size / 4 ); for ( std::set<EntityProc,EntityLess>::iterator i = send_closure.begin() ; i != send_closure.end() ; ++i ) { CommBuffer & buffer = comm.send_buffer( i->second ); Entity & entity = * i->first ; pack_entity_info( buffer , entity ); pack_field_values( buffer , entity ); } comm.communicate(); for ( unsigned p = 0 ; p < p_size ; ++p ) { CommBuffer & buf = comm.recv_buffer(p); while ( buf.remaining() ) { PartVector parts ; std::vector<Relation> relations ; EntityKey key ; unsigned owner = ~0u ; unpack_entity_info( buf, *this, key, owner, parts, relations ); // Received entity information will be correct, // modulo the owned and shared parts remove( parts , meta.globally_shared_part() ); if ( owner == p_rank ) { // Must have the locally_owned_part insert( parts , meta.locally_owned_part() ); } else { // Must not have the locally_owned_part remove( parts , meta.locally_owned_part() ); } std::pair<Entity*,bool> result = m_entity_repo.internal_create_entity( key ); m_entity_repo.log_created_parallel_copy( *(result.first) ); // The entity was copied and not created. m_entity_repo.set_entity_owner_rank( *(result.first), owner); internal_change_entity_parts( *result.first , parts , PartVector() ); declare_relation( *result.first , relations ); if ( ! unpack_field_values( buf , * result.first , error_msg ) ) { ++error_count ; } } } all_reduce( p_comm , ReduceSum<1>( & error_count ) ); if ( error_count ) { throw std::runtime_error( error_msg.str() ); } // Any entity that I sent and is not in an owned closure is deleted. // The owned closure will be effected by received entities, so can // only clean up after the newly owned entities have been received. // Destroy backwards so as not to invalidate closures in the process. { Entity * entity = NULL ; for ( std::set<EntityProc,EntityLess>::iterator i = send_closure.end() ; i != send_closure.begin() ; ) { Entity * e = (--i)->first ; // The same entity may be sent to more than one process. // Only evaluate it once. if ( entity != e ) { entity = e ; if ( ! member_of_owned_closure( *e , p_rank ) ) { if ( ! destroy_entity( e ) ) { throw std::logic_error(std::string("BulkData::destroy_entity FAILED")); } } } } } send_closure.clear(); // Has been invalidated } }