Sierra Toolkit Version of the Day
BulkDataRelation.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/parallel/ParallelComm.hpp>
00019 #include <stk_util/parallel/ParallelReduce.hpp>
00020 
00021 #include <stk_mesh/base/BulkData.hpp>
00022 #include <stk_mesh/base/MetaData.hpp>
00023 #include <stk_mesh/base/Comm.hpp>
00024 #include <stk_mesh/base/FieldData.hpp>
00025 #include <stk_mesh/base/Trace.hpp>
00026 
00027 namespace stk {
00028 namespace mesh {
00029 
00030 void set_field_relations( Entity & e_from ,
00031                           Entity & e_to ,
00032                           const unsigned ident )
00033 {
00034   const std::vector<FieldRelation> & field_rels =
00035     MetaData::get(e_from).get_field_relations();
00036 
00037   for ( std::vector<FieldRelation>::const_iterator
00038         j = field_rels.begin() ; j != field_rels.end() ; ++j ) {
00039 
00040     const FieldRelation & fr = *j ;
00041 
00042     void ** const ptr = (void**) field_data( * fr.m_root , e_from );
00043 
00044     if ( ptr ) {
00045 
00046       void * const src = field_data( * fr.m_target , e_to );
00047 
00048       const size_t number =
00049         field_data_size(*fr.m_root,e_from) / sizeof(void*);
00050 
00051       const size_t offset =
00052          (*fr.m_function)( e_from.entity_rank() ,
00053                            e_to.entity_rank() , ident );
00054 
00055       if ( offset < number ) {
00056         ptr[ offset ] = src ;
00057       }
00058     }
00059   }
00060 }
00061 
00062 namespace {
00063 
00064 void clear_field_relations( Entity & e_from ,
00065                             const unsigned type ,
00066                             const unsigned ident )
00067 {
00068   const std::vector<FieldRelation> & field_rels =
00069     MetaData::get(e_from).get_field_relations();
00070 
00071   for ( std::vector<FieldRelation>::const_iterator
00072         j = field_rels.begin() ; j != field_rels.end() ; ++j ) {
00073 
00074     const FieldRelation & fr = *j ;
00075 
00076     void ** const ptr = (void**) field_data( * fr.m_root , e_from );
00077 
00078     if ( ptr ) {
00079 
00080       const size_t number =
00081         field_data_size(*fr.m_root,e_from) / sizeof(void*);
00082 
00083       const size_t offset =
00084         (*fr.m_function)( e_from.entity_rank() , type , ident );
00085 
00086       if ( offset < number ) {
00087         ptr[ offset ] = NULL ;
00088       }
00089     }
00090   }
00091 }
00092 
00093 } // empty namespace
00094 
00095 //----------------------------------------------------------------------
00096 
00097 void BulkData::require_valid_relation( const char action[] ,
00098                                        const BulkData & mesh ,
00099                                        const Entity   & e_from ,
00100                                        const Entity   & e_to )
00101 {
00102   const bool error_mesh_from = & mesh != & BulkData::get(e_from);
00103   const bool error_mesh_to   = & mesh != & BulkData::get(e_to);
00104   const bool error_type      = e_from.entity_rank() <= e_to.entity_rank();
00105   const bool error_nil_from  = EntityLogDeleted == e_from.log_query();
00106   const bool error_nil_to    = EntityLogDeleted == e_to.log_query();
00107 
00108   if ( error_mesh_from || error_mesh_to || error_type ||
00109        error_nil_from || error_nil_to ) {
00110     std::ostringstream msg ;
00111 
00112     msg << "Could not " << action << " relation from entity "
00113         << print_entity_key(e_from) << " to entity "
00114         << print_entity_key(e_to) << "\n";
00115 
00116     ThrowErrorMsgIf( error_mesh_from || error_mesh_to,
00117                      msg.str() << (error_mesh_from ? "e_from" : "e_to" ) <<
00118                      " not member of this mesh");
00119     ThrowErrorMsgIf( error_nil_from  || error_nil_to,
00120                      msg.str() << (error_mesh_from ? "e_from" : "e_to" ) <<
00121                      " was destroyed");
00122     ThrowErrorMsgIf( error_type, msg.str() <<
00123                      "A relation must be from higher to lower ranking entity");
00124   }
00125 }
00126 
00127 //----------------------------------------------------------------------
00128 
00129 void BulkData::declare_relation( Entity & e_from ,
00130                                  Entity & e_to ,
00131                                  const RelationIdentifier local_id )
00132 {
00133   TraceIfWatching("stk::mesh::BulkData::declare_relation", LOG_ENTITY, e_from.key());
00134   TraceIfWatchingDec("stk::mesh::BulkData::declare_relation", LOG_ENTITY, e_to.key(), 1);
00135   DiagIfWatching(LOG_ENTITY, e_from.key(),
00136                  "from: " << e_from << ";  " <<
00137                  "to: " << e_to << ";  " <<
00138                  "id: " << local_id);
00139   DiagIfWatching(LOG_ENTITY, e_to.key(),
00140                  "from: " << e_from << ";  " <<
00141                  "to: " << e_to << ";  " <<
00142                  "id: " << local_id);
00143 
00144   require_ok_to_modify();
00145 
00146   require_valid_relation( "declare" , *this , e_from , e_to );
00147 
00148   // TODO: Don't throw if exact relation already exists, that should be a no-op.
00149   // Should be an exact match if relation of local_id already exists (e_to should be the same).
00150   m_entity_repo.declare_relation( e_from, e_to, local_id, m_sync_count);
00151 
00152   OrdinalVector add , empty ;
00153 
00154   // Deduce and set new part memberships:
00155 
00156   induced_part_membership( e_from, empty, e_to.entity_rank(), local_id, add );
00157 
00158   internal_change_entity_parts( e_to , add , empty );
00159 
00160   set_field_relations( e_from , e_to , local_id );
00161 }
00162 
00163 //----------------------------------------------------------------------
00164 
00165 void BulkData::declare_relation( Entity & entity ,
00166                                  const std::vector<Relation> & rel )
00167 {
00168   require_ok_to_modify();
00169 
00170   const unsigned erank = entity.entity_rank();
00171 
00172   std::vector<Relation>::const_iterator i ;
00173   for ( i = rel.begin() ; i != rel.end() ; ++i ) {
00174     Entity & e = * i->entity();
00175     const unsigned n = i->identifier();
00176     if ( e.entity_rank() < erank ) {
00177       declare_relation( entity , e , n );
00178     }
00179     else if ( erank < e.entity_rank() ) {
00180       declare_relation( e , entity , n );
00181     }
00182     else {
00183       ThrowErrorMsg("Given entities of the same entity rank. entity is " <<
00184                     print_entity_key(entity));
00185     }
00186   }
00187 }
00188 
00189 //----------------------------------------------------------------------
00190 
00191 bool BulkData::destroy_relation( Entity & e_from ,
00192                                  Entity & e_to,
00193                                  const RelationIdentifier local_id )
00194 {
00195   TraceIfWatching("stk::mesh::BulkData::destroy_relation", LOG_ENTITY, e_from.key());
00196   TraceIfWatchingDec("stk::mesh::BulkData::destroy_relation", LOG_ENTITY, e_to.key(), 1);
00197   DiagIfWatching(LOG_ENTITY, e_from.key(),
00198                  "from: " << e_from << ";  " <<
00199                  "to: " << e_to << ";  " <<
00200                  "id: " << local_id);
00201   DiagIfWatching(LOG_ENTITY, e_to.key(),
00202                  "from: " << e_from << ";  " <<
00203                  "to: " << e_to << ";  " <<
00204                  "id: " << local_id);
00205 
00206   require_ok_to_modify();
00207 
00208   require_valid_relation( "destroy" , *this , e_from , e_to );
00209 
00210   //------------------------------
00211   // When removing a relationship may need to
00212   // remove part membership and set field relation pointer to NULL
00213 
00214   if ( parallel_size() < 2 || m_entity_comm_map.sharing(e_to.key()).empty() ) {
00215 
00216     //------------------------------
00217     // 'keep' contains the parts deduced from kept relations
00218     // 'del'  contains the parts deduced from deleted relations
00219     //        that are not in 'keep'
00220     // Only remove these part memberships the entity is not shared.
00221     // If the entity is shared then wait until modificaton_end_synchronize.
00222     //------------------------------
00223 
00224     OrdinalVector del, keep, empty;
00225 
00226     // For all relations that are *not* being deleted, add induced parts for
00227     // these relations to the 'keep' vector
00228     for ( PairIterRelation i = e_to.relations(); !i.empty(); ++i ) {
00229       if (e_to.entity_rank() < i->entity_rank()) { // Need to look at back rels only
00230         if ( !( i->entity() == & e_from && i->identifier() == local_id ) ) {
00231           induced_part_membership( * i->entity(), empty, e_to.entity_rank(),
00232                                    i->identifier(), keep,
00233                                    false /*Do not look at supersets*/);
00234         }
00235       }
00236     }
00237 
00238     // Find the relation this is being deleted and add the parts that are
00239     // induced from that relation (and that are not in 'keep') to 'del'
00240     for ( PairIterRelation i = e_from.relations() ; !i.empty() ; ++i ) {
00241       if ( i->entity() == & e_to && i->identifier() == local_id ) {
00242         induced_part_membership( e_from, keep, e_to.entity_rank(),
00243                                  i->identifier(), del,
00244                                  false /*Do not look at supersets*/);
00245         clear_field_relations( e_from , e_to.entity_rank() ,
00246                                i->identifier() );
00247         break; // at most 1 relation can match our specification
00248       }
00249     }
00250 
00251     if ( !del.empty() ) {
00252       internal_change_entity_parts( e_to , empty , del );
00253     }
00254   }
00255   else {
00256     // Just clear the field, part membership will be handled by modification end
00257     for ( PairIterRelation i = e_from.relations() ; !i.empty() ; ++i ) {
00258       if ( i->entity() == & e_to && i->identifier() == local_id ) {
00259         clear_field_relations( e_from , e_to.entity_rank() ,
00260                                i->identifier() );
00261         break; // at most 1 relation can match our specification
00262       }
00263     }
00264   }
00265 
00266   //delete relations from the entities
00267   return m_entity_repo.destroy_relation( e_from, e_to, local_id);
00268 }
00269 
00270 //----------------------------------------------------------------------
00271 // Deduce propagation of part membership changes to a 'from' entity
00272 // to the related 'to' entities.  There can be both additions and
00273 // removals.
00274 
00275 void BulkData::internal_propagate_part_changes(
00276   Entity           & entity ,
00277   const PartVector & removed )
00278 {
00279   TraceIfWatching("stk::mesh::BulkData::internal_propagate_part_changes",
00280                   LOG_ENTITY,
00281                   entity.key());
00282   DiagIfWatching(LOG_ENTITY, entity.key(), "entity state: " << entity);
00283   DiagIfWatching(LOG_ENTITY, entity.key(), "Removed: " << removed);
00284 
00285   const unsigned etype = entity.entity_rank();
00286 
00287   PairIterRelation rel = entity.relations();
00288 
00289   OrdinalVector to_del , to_add , empty ;
00290 
00291   for ( ; ! rel.empty() ; ++rel ) {
00292     const unsigned rel_type  = rel->entity_rank();
00293     const unsigned rel_ident = rel->identifier();
00294 
00295     if ( rel_type < etype ) { // a 'to' entity
00296 
00297       Entity & e_to = * rel->entity();
00298 
00299       to_del.clear();
00300       to_add.clear();
00301       empty.clear();
00302 
00303       // Induce part membership from this relationship to
00304       // pick up any additions.
00305       induced_part_membership( entity, empty,
00306                                rel_type, rel_ident, to_add );
00307 
00308       if ( ! removed.empty() ) {
00309         // Something was removed from the 'from' entity,
00310         // deduce what may have to be removed from the 'to' entity.
00311 
00312         // Deduce parts for 'e_to' from all upward relations.
00313         // Any non-parallel part that I removed that is not deduced for
00314         // 'e_to' must be removed from 'e_to'
00315 
00316         for ( PairIterRelation
00317               to_rel = e_to.relations(); ! to_rel.empty() ; ++to_rel ) {
00318           if ( e_to.entity_rank() < to_rel->entity_rank() &&
00319                & entity != to_rel->entity() /* Already did this entity */ ) {
00320             // Relation from to_rel->entity() to e_to
00321             induced_part_membership( * to_rel->entity(), empty,
00322                                      e_to.entity_rank(),
00323                                      to_rel->identifier(),
00324                                      to_add );
00325           }
00326         }
00327 
00328         OrdinalVector::const_iterator to_add_begin = to_add.begin(),
00329                                       to_add_end   = to_add.end();
00330 
00331         for ( PartVector::const_iterator
00332               j = removed.begin() ; j != removed.end() ; ++j ) {
00333           if ( ! contains_ordinal( to_add_begin, to_add_end , (*j)->mesh_meta_data_ordinal() ) ) {
00334             induced_part_membership( **j, etype, rel_type, rel_ident, to_del );
00335           }
00336         }
00337       }
00338 
00339       if ( parallel_size() < 2 || m_entity_comm_map.sharing(e_to.key()).empty() ) {
00340         // Entirely local, ok to remove memberships now
00341         internal_change_entity_parts( e_to , to_add , to_del );
00342       }
00343       else {
00344         // Shared, do not remove memberships now.
00345         // Wait until modification_end.
00346         internal_change_entity_parts( e_to , to_add , empty );
00347       }
00348 
00349       set_field_relations( entity, e_to, rel_ident );
00350     }
00351     else if ( etype < rel_type ) { // a 'from' entity
00352       Entity & e_from = * rel->entity();
00353 
00354       set_field_relations( e_from, entity, rel_ident );
00355     }
00356   }
00357 }
00358 
00359 void BulkData::internal_propagate_part_changes(
00360   Entity           & entity ,
00361   const OrdinalVector & removed )
00362 {
00363   TraceIfWatching("stk::mesh::BulkData::internal_propagate_part_changes",
00364                   LOG_ENTITY,
00365                   entity.key());
00366   DiagIfWatching(LOG_ENTITY, entity.key(), "entity state: " << entity);
00367   DiagIfWatching(LOG_ENTITY, entity.key(), "Removed: " << removed);
00368 
00369   const unsigned etype = entity.entity_rank();
00370 
00371   PairIterRelation rel = entity.relations();
00372 
00373   OrdinalVector to_del , to_add , empty ;
00374 
00375   const PartVector& all_parts = m_mesh_meta_data.get_parts();
00376 
00377   for ( ; ! rel.empty() ; ++rel ) {
00378     const unsigned rel_type  = rel->entity_rank();
00379     const unsigned rel_ident = rel->identifier();
00380 
00381     if ( rel_type < etype ) { // a 'to' entity
00382 
00383       Entity & e_to = * rel->entity();
00384 
00385       to_del.clear();
00386       to_add.clear();
00387       empty.clear();
00388 
00389       // Induce part membership from this relationship to
00390       // pick up any additions.
00391       induced_part_membership( entity, empty,
00392                                rel_type, rel_ident, to_add );
00393 
00394       if ( ! removed.empty() ) {
00395         // Something was removed from the 'from' entity,
00396         // deduce what may have to be removed from the 'to' entity.
00397 
00398         // Deduce parts for 'e_to' from all upward relations.
00399         // Any non-parallel part that I removed that is not deduced for
00400         // 'e_to' must be removed from 'e_to'
00401 
00402         for ( PairIterRelation
00403               to_rel = e_to.relations(); ! to_rel.empty() ; ++to_rel ) {
00404           if ( e_to.entity_rank() < to_rel->entity_rank() &&
00405                & entity != to_rel->entity() /* Already did this entity */ ) {
00406             // Relation from to_rel->entity() to e_to
00407             induced_part_membership( * to_rel->entity(), empty,
00408                                      e_to.entity_rank(),
00409                                      to_rel->identifier(),
00410                                      to_add );
00411           }
00412         }
00413 
00414         OrdinalVector::const_iterator to_add_begin = to_add.begin(),
00415                                       to_add_end   = to_add.end();
00416 
00417         for ( OrdinalVector::const_iterator
00418               j = removed.begin() ; j != removed.end() ; ++j ) {
00419           if ( ! contains_ordinal( to_add_begin, to_add_end , *j ) ) {
00420             induced_part_membership( *all_parts[*j], etype, rel_type, rel_ident, to_del );
00421           }
00422         }
00423       }
00424 
00425       if ( parallel_size() < 2 || m_entity_comm_map.sharing(e_to.key()).empty() ) {
00426         // Entirely local, ok to remove memberships now
00427         internal_change_entity_parts( e_to , to_add , to_del );
00428       }
00429       else {
00430         // Shared, do not remove memberships now.
00431         // Wait until modification_end.
00432         internal_change_entity_parts( e_to , to_add , empty );
00433       }
00434 
00435       set_field_relations( entity, e_to, rel_ident );
00436     }
00437     else if ( etype < rel_type ) { // a 'from' entity
00438       Entity & e_from = * rel->entity();
00439 
00440       set_field_relations( e_from, entity, rel_ident );
00441     }
00442   }
00443 }
00444 
00445 //----------------------------------------------------------------------
00446 //----------------------------------------------------------------------
00447 
00448 } // namespace mesh
00449 } // namespace stk
00450 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines