Sierra Toolkit Version of the Day
BucketRepository.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 
00009 #include <sstream>
00010 #include <cstdlib>
00011 #include <stdexcept>
00012 
00013 #include <stk_mesh/baseImpl/BucketRepository.hpp>
00014 #include <stk_mesh/baseImpl/EntityRepository.hpp>
00015 #include <stk_mesh/base/BulkData.hpp>
00016 #include <stk_mesh/base/Bucket.hpp>
00017 
00018 namespace stk {
00019 namespace mesh {
00020 namespace impl {
00021 
00022 //----------------------------------------------------------------------
00023 namespace {
00024 
00025 void * local_malloc( size_t n )
00026 {
00027   void * const ptr = std::malloc( n );
00028 
00029   if ( NULL == ptr ) {
00030     std::ostringstream msg ;
00031     msg << "stk::mesh::impl::BucketImpl::declare_bucket FAILED malloc( " << n << " )" ;
00032     throw std::runtime_error( msg.str() );
00033   }
00034 
00035   return ptr ;
00036 }
00037 
00038 
00039 } // namespace
00040 
00041 //----------------------------------------------------------------------
00042 
00043 namespace {
00044 
00045 inline unsigned align( size_t nb )
00046 {
00047   enum { BYTE_ALIGN = 16 };
00048   const unsigned gap = nb % BYTE_ALIGN ;
00049   if ( gap ) { nb += BYTE_ALIGN - gap ; }
00050   return nb ;
00051 }
00052 
00053 struct FieldRestrictionLess {
00054   bool operator()( const FieldBase::Restriction & lhs ,
00055                    const EntityKey & rhs ) const
00056     { return lhs.key < rhs ; }
00057 };
00058 
00059 const FieldBase::Restriction & empty_field_restriction()
00060 {
00061   static const FieldBase::Restriction empty ;
00062   return empty ;
00063 }
00064 
00065 const FieldBase::Restriction & dimension( const FieldBase & field ,
00066                                           unsigned etype ,
00067                                           const unsigned num_part_ord ,
00068                                           const unsigned part_ord[] ,
00069                                           const char * const method )
00070 {
00071   const FieldBase::Restriction & empty = empty_field_restriction();
00072   const FieldBase::Restriction * dim = & empty ;
00073 
00074   const std::vector<FieldBase::Restriction> & dim_map = field.restrictions();
00075   const std::vector<FieldBase::Restriction>::const_iterator iend = dim_map.end();
00076         std::vector<FieldBase::Restriction>::const_iterator ibeg = dim_map.begin();
00077 
00078   for ( unsigned i = 0 ; i < num_part_ord && iend != ibeg ; ++i ) {
00079 
00080     const EntityKey key = EntityKey(etype,part_ord[i]);
00081 
00082     ibeg = std::lower_bound( ibeg , iend , key , FieldRestrictionLess() );
00083 
00084     if ( iend != ibeg && ibeg->key == key ) {
00085       if ( dim == & empty ) { dim = & *ibeg ; }
00086 
00087       if ( Compare< MaximumFieldDimension >::
00088              not_equal( ibeg->stride , dim->stride ) ) {
00089 
00090         Part & p_old = field.mesh_meta_data().get_part( ibeg->ordinal() );
00091         Part & p_new = field.mesh_meta_data().get_part( dim->ordinal() );
00092 
00093         std::ostringstream msg ;
00094         msg << method ;
00095         msg << " FAILED WITH INCOMPATIBLE DIMENSIONS FOR " ;
00096         msg << field ;
00097         msg << " Part[" << p_old.name() ;
00098         msg << "] and Part[" << p_new.name() ;
00099         msg << "]" ;
00100 
00101         throw std::runtime_error( msg.str() );
00102       }
00103     }
00104   }
00105 
00106   return *dim ;
00107 }
00108 
00109 } // namespace
00110 
00111 //----------------------------------------------------------------------
00112 
00113 
00114 BucketRepository::BucketRepository(
00115     BulkData & mesh,
00116     unsigned bucket_capacity,
00117     unsigned entity_rank_count,
00118     EntityRepository & entity_repo
00119     )
00120   :m_mesh(mesh),
00121    m_bucket_capacity(bucket_capacity),
00122    m_buckets(entity_rank_count),
00123    m_nil_bucket(NULL),
00124    m_entity_repo(entity_repo)
00125 {
00126 }
00127 
00128 
00129 BucketRepository::~BucketRepository()
00130 {
00131   // Destroy buckets, which were *not* allocated by the set.
00132 
00133   try {
00134     for ( std::vector< std::vector<Bucket*> >::iterator
00135           i = m_buckets.end() ; i != m_buckets.begin() ; ) {
00136       try {
00137         std::vector<Bucket*> & kset = *--i ;
00138 
00139         while ( ! kset.empty() ) {
00140           try { destroy_bucket( kset.back() ); } catch(...) {}
00141           kset.pop_back();
00142         }
00143         kset.clear();
00144       } catch(...) {}
00145     }
00146     m_buckets.clear();
00147   } catch(...) {}
00148 
00149   try { if ( m_nil_bucket ) destroy_bucket( m_nil_bucket ); } catch(...) {}
00150 }
00151 
00152 
00153 //----------------------------------------------------------------------
00154 // The current 'last' bucket in a family is to be deleted.
00155 // The previous 'last' bucket becomes the new 'last' bucket in the family.
00156 
00157 void BucketRepository::destroy_bucket( const unsigned & entity_rank , Bucket * bucket_to_be_deleted )
00158 {
00159   static const char method[] = "stk::mesh::impl::BucketRepository::destroy_bucket" ;
00160 
00161   m_mesh.mesh_meta_data().assert_entity_rank( method, entity_rank );
00162   std::vector<Bucket *> & bucket_set = m_buckets[entity_rank];
00163 
00164   Bucket * const first = bucket_to_be_deleted->m_bucketImpl.first_bucket_in_family();
00165 
00166   if ( 0 != bucket_to_be_deleted->size() || bucket_to_be_deleted != first->m_bucketImpl.get_bucket_family_pointer() ) {
00167     throw std::logic_error(std::string(method));
00168   }
00169 
00170   std::vector<Bucket*>::iterator ik = lower_bound(bucket_set, bucket_to_be_deleted->key());
00171 
00172   if ( ik == bucket_set.end() ) {
00173     throw std::logic_error(std::string(method));
00174   }
00175 
00176   if ( bucket_to_be_deleted != *ik ) {
00177     throw std::logic_error(std::string(method));
00178   }
00179 
00180   ik = bucket_set.erase( ik );
00181 
00182   if ( first != bucket_to_be_deleted ) {
00183 
00184     if ( ik == bucket_set.begin() ) {
00185       throw std::logic_error(std::string(method));
00186     }
00187 
00188     first->m_bucketImpl.set_last_bucket_in_family( *--ik );
00189 
00190     if ( 0 == first->m_bucketImpl.get_bucket_family_pointer()->size() ) {
00191       throw std::logic_error(std::string(method));
00192     }
00193   }
00194 
00195   destroy_bucket( bucket_to_be_deleted );
00196 }
00197 
00198 //----------------------------------------------------------------------
00199 void BucketRepository::destroy_bucket( Bucket * bucket )
00200 {
00201   bucket->~Bucket();
00202   std::free( bucket );
00203 }
00204 
00205 //
00206 //----------------------------------------------------------------------
00207 // The input part ordinals are complete and contain all supersets.
00208 void
00209 BucketRepository::declare_nil_bucket()
00210 {
00211   if (m_nil_bucket == NULL) {
00212     unsigned field_count = m_mesh.mesh_meta_data().get_fields().size();
00213 
00214     //----------------------------------
00215     // Field map gives NULL for all field data.
00216 
00217     impl::BucketImpl::DataMap * field_map =
00218       reinterpret_cast<impl::BucketImpl::DataMap*>(
00219         local_malloc( sizeof(impl::BucketImpl::DataMap) * ( field_count + 1 )));
00220 
00221     const FieldBase::Restriction & dim = empty_field_restriction();
00222 
00223     for ( unsigned i = 0 ; i < field_count ; ++i ) {
00224       field_map[ i ].m_base = 0 ;
00225       field_map[ i ].m_size = 0 ;
00226       field_map[ i ].m_stride = dim.stride ;
00227     }
00228     field_map[ field_count ].m_base   = 0 ;
00229     field_map[ field_count ].m_size   = 0 ;
00230     field_map[ field_count ].m_stride = NULL ;
00231 
00232     //----------------------------------
00233     // Allocation size:  sizeof(Bucket) + key_size * sizeof(unsigned);
00234 
00235     const unsigned alloc_size = align( sizeof(Bucket) ) +
00236                                 align( sizeof(unsigned) * 2 );
00237 
00238     // All fields checked and sized, Ready to allocate
00239 
00240     void * const alloc_ptr = local_malloc( alloc_size );
00241 
00242     unsigned char * ptr = reinterpret_cast<unsigned char *>( alloc_ptr );
00243 
00244     ptr += align( sizeof( Bucket ) );
00245 
00246     unsigned * const new_key = reinterpret_cast<unsigned *>( ptr );
00247 
00248     // Key layout:
00249     // { part_count + 1 , { part_ordinals } , family_count }
00250 
00251     new_key[0] = 1 ; // part_count + 1
00252     new_key[1] = 0 ; // family_count
00253 
00254     const unsigned bad_entity_rank = ~0u ;
00255 
00256     Bucket * bucket =
00257       new( alloc_ptr ) Bucket( m_mesh , bad_entity_rank , new_key ,
00258                               alloc_size , 0 , field_map , NULL );
00259 
00260     bucket->m_bucketImpl.set_bucket_family_pointer( bucket );
00261 
00262     //----------------------------------
00263 
00264     m_nil_bucket = bucket;
00265   }
00266 }
00267 
00268 
00269 //----------------------------------------------------------------------
00270 // The input part ordinals are complete and contain all supersets.
00271 Bucket *
00272 BucketRepository::declare_bucket(
00273                         const unsigned arg_entity_rank ,
00274                         const unsigned part_count ,
00275                         const unsigned part_ord[] ,
00276                         const std::vector< FieldBase * > & field_set
00277                               )
00278 {
00279   enum { KEY_TMP_BUFFER_SIZE = 64 };
00280 
00281   static const char method[] = "stk::mesh::impl::BucketRepository::declare_bucket" ;
00282 
00283   const unsigned max = ~(0u);
00284   const size_t   num_fields = field_set.size();
00285 
00286   m_mesh.mesh_meta_data().assert_entity_rank( method, arg_entity_rank );
00287   std::vector<Bucket *> & bucket_set = m_buckets[ arg_entity_rank ];
00288 
00289   //----------------------------------
00290   // For performance try not to allocate a temporary.
00291 
00292   unsigned key_tmp_buffer[ KEY_TMP_BUFFER_SIZE ];
00293 
00294   std::vector<unsigned> key_tmp_vector ;
00295 
00296   const unsigned key_size = 2 + part_count ;
00297 
00298   unsigned * const key =
00299     ( key_size <= KEY_TMP_BUFFER_SIZE )
00300     ? key_tmp_buffer
00301     : ( key_tmp_vector.resize( key_size ) , & key_tmp_vector[0] );
00302 
00303   //----------------------------------
00304   // Key layout:
00305   // { part_count + 1 , { part_ordinals } , family_count }
00306   // Thus family_count = key[ key[0] ]
00307   //
00308   // for upper bound search use the maximum key.
00309 
00310   key[ key[0] = part_count + 1 ] = max ;
00311 
00312   {
00313     unsigned * const k = key + 1 ;
00314     for ( unsigned i = 0 ; i < part_count ; ++i ) { k[i] = part_ord[i] ; }
00315   }
00316 
00317   //----------------------------------
00318   // Bucket family has all of the same parts.
00319   // Look for the last bucket in this family:
00320 
00321   const std::vector<Bucket*>::iterator ik = lower_bound( bucket_set , key );
00322 
00323   //----------------------------------
00324   // If a member of the bucket family has space, it is the last one
00325   // since buckets are kept packed.
00326   const bool bucket_family_exists =
00327     ik != bucket_set.begin() && bucket_part_equal( ik[-1]->key() , key );
00328 
00329   Bucket * const last_bucket = bucket_family_exists ? ik[-1] : NULL ;
00330 
00331   Bucket          * bucket    = NULL ;
00332   impl::BucketImpl::DataMap * field_map = NULL ;
00333 
00334   if ( last_bucket == NULL ) { // First bucket in this family
00335     key[ key[0] ] = 0 ; // Set the key's family count to zero
00336   }
00337   else { // Last bucket present, can it hold one more entity?
00338 
00339     if ( 0 == last_bucket->size() ) {
00340       throw std::logic_error( std::string(method) );
00341     }
00342 
00343     field_map = last_bucket->m_bucketImpl.get_field_map();
00344 
00345     const unsigned last_count = last_bucket->key()[ key[0] ];
00346 
00347     const unsigned cap = last_bucket->capacity();
00348 
00349     if ( last_bucket->size() < cap ) {
00350       bucket = last_bucket ;
00351     }
00352     else if ( last_count < max ) {
00353       key[ key[0] ] = 1 + last_count ; // Increment the key's family count.
00354     }
00355     else {
00356       // ERROR insane number of buckets!
00357       std::string msg ;
00358       msg.append( method );
00359       msg.append( " FAILED due to insanely large number of buckets" );
00360       throw std::logic_error( msg );
00361     }
00362   }
00363 
00364   //----------------------------------
00365   // Family's field map does not exist, create it:
00366 
00367   if ( NULL == field_map ) {
00368 
00369     field_map = reinterpret_cast<impl::BucketImpl::DataMap*>(
00370                 local_malloc( sizeof(impl::BucketImpl::DataMap) * ( num_fields + 1 )));
00371 
00372     // Start field data memory after the array of member entity pointers:
00373     unsigned value_offset = align( sizeof(Entity*) * m_bucket_capacity );
00374 
00375     for ( unsigned i = 0 ; i < num_fields ; ++i ) {
00376       const FieldBase  & field = * field_set[i] ;
00377 
00378       unsigned value_size = 0 ;
00379 
00380       const FieldBase::Restriction & dim =
00381         dimension( field, arg_entity_rank, part_count, part_ord, method);
00382 
00383       if ( dim.stride[0] ) { // Exists
00384 
00385         const unsigned type_stride = field.data_traits().stride_of ;
00386         const unsigned field_rank  = field.rank();
00387 
00388         value_size = type_stride *
00389           ( field_rank ? dim.stride[ field_rank - 1 ] : 1 );
00390       }
00391 
00392       field_map[i].m_base = value_offset ;
00393       field_map[i].m_size = value_size ;
00394       field_map[i].m_stride = dim.stride ;
00395 
00396       value_offset += align( value_size * m_bucket_capacity );
00397     }
00398     field_map[ num_fields ].m_base  = value_offset ;
00399     field_map[ num_fields ].m_size = 0 ;
00400     field_map[ num_fields ].m_stride = NULL ;
00401   }
00402 
00403   //----------------------------------
00404 
00405   if ( NULL == bucket ) {
00406 
00407     // Required bucket does not exist, must allocate and insert
00408     //
00409     // Allocation size:
00410     //   sizeof(Bucket) +
00411     //   key_size * sizeof(unsigned) +
00412     //   sizeof(Entity*) * capacity() +
00413     //   sum[number_of_fields]( fieldsize * capacity )
00414     //
00415     // The field_map[ num_fields ].m_base spans
00416     //   sizeof(Entity*) * capacity() +
00417     //   sum[number_of_fields]( fieldsize * capacity )
00418 
00419     const unsigned alloc_size = align( sizeof(Bucket) ) +
00420                                 align( sizeof(unsigned) * key_size ) +
00421                                 field_map[ num_fields ].m_base ;
00422 
00423     // All fields checked and sized, Ready to allocate
00424 
00425     void * const alloc_ptr = local_malloc( alloc_size );
00426 
00427     unsigned char * ptr = reinterpret_cast<unsigned char *>( alloc_ptr );
00428 
00429     ptr += align( sizeof( Bucket ) );
00430 
00431     unsigned * const new_key = reinterpret_cast<unsigned *>( ptr );
00432 
00433     ptr += align( sizeof(unsigned) * key_size );
00434 
00435     Entity ** const entity_array = reinterpret_cast<Entity**>( ptr );
00436 
00437     for ( unsigned i = 0 ; i < key_size ; ++i ) { new_key[i] = key[i] ; }
00438 
00439     bucket = new( alloc_ptr ) Bucket( m_mesh, arg_entity_rank , new_key,
00440                                       alloc_size, m_bucket_capacity ,
00441                                       field_map , entity_array );
00442 
00443     Bucket * first_bucket = last_bucket ? last_bucket->m_bucketImpl.first_bucket_in_family() : bucket ;
00444 
00445     bucket->m_bucketImpl.set_first_bucket_in_family(first_bucket); // Family members point to first bucket
00446 
00447     first_bucket->m_bucketImpl.set_last_bucket_in_family(bucket); // First bucket points to new last bucket
00448 
00449     bucket_set.insert( ik , bucket );
00450   }
00451 
00452   //----------------------------------
00453 
00454   return bucket ;
00455 }
00456 
00457 
00458 
00459 //----------------------------------------------------------------------
00460 
00461 void BucketRepository::zero_fields( Bucket & k_dst , unsigned i_dst )
00462 {
00463   k_dst.m_bucketImpl.zero_fields(i_dst);
00464 }
00465 
00466 void BucketRepository::copy_fields( Bucket & k_dst , unsigned i_dst ,
00467                           Bucket & k_src , unsigned i_src )
00468 {
00469   k_dst.m_bucketImpl.replace_fields(i_dst,k_src,i_src);
00470 }
00471 
00472 //----------------------------------------------------------------------
00473 
00474 void BucketRepository::update_field_data_states() const
00475 {
00476   for ( std::vector< std::vector<Bucket*> >::const_iterator
00477         i = m_buckets.begin() ; i != m_buckets.end() ; ++i ) {
00478 
00479     const std::vector<Bucket*> & kset = *i ;
00480 
00481     for ( std::vector<Bucket*>::const_iterator
00482           ik = kset.begin() ; ik != kset.end() ; ++ik ) {
00483       (*ik)->m_bucketImpl.update_state();
00484     }
00485   }
00486 }
00487 
00488 
00489 //----------------------------------------------------------------------
00490 
00491 const std::vector<Bucket*> & BucketRepository::buckets( unsigned type ) const
00492 {
00493   static const char method[]= "stk::mesh::impl::BucketRepository::buckets" ;
00494 
00495   m_mesh.mesh_meta_data().assert_entity_rank( method , type );
00496 
00497   return m_buckets[ type ];
00498 }
00499 
00500 //----------------------------------------------------------------------
00501 
00502 
00503 void BucketRepository::internal_sort_bucket_entities()
00504 {
00505   for ( unsigned entity_rank = 0 ;
00506                  entity_rank < m_buckets.size() ; ++entity_rank ) {
00507 
00508     std::vector<Bucket*> & buckets = m_buckets[ entity_rank ];
00509 
00510     size_t bk = 0 ; // Offset to first bucket of the family
00511     size_t ek = 0 ; // Offset to end   bucket of the family
00512 
00513     for ( ; bk < buckets.size() ; bk = ek ) {
00514       Bucket * b_scratch = NULL ;
00515       Bucket * ik_vacant = buckets[bk]->m_bucketImpl.last_bucket_in_family();
00516       unsigned ie_vacant = ik_vacant->size();
00517 
00518       if ( ik_vacant->capacity() <= ie_vacant ) {
00519         // Have to create a bucket just for the scratch space...
00520         const unsigned * const bucket_key = buckets[bk]->key() ;
00521         const unsigned         part_count = bucket_key[0] - 1 ;
00522         const unsigned * const part_ord   = bucket_key + 1 ;
00523 
00524         b_scratch = declare_bucket( entity_rank ,
00525             part_count , part_ord ,
00526             m_mesh.mesh_meta_data().get_fields() );
00527 
00528         ik_vacant = b_scratch ;
00529         ie_vacant = 0 ;
00530       }
00531 
00532       ik_vacant->m_bucketImpl.replace_entity( ie_vacant , NULL ) ;
00533 
00534       // Determine offset to the end bucket in this family:
00535       while ( ek < buckets.size() && ik_vacant != buckets[ek] ) { ++ek ; }
00536       ++ek ;
00537 
00538       unsigned count = 0 ;
00539       for ( size_t ik = bk ; ik != ek ; ++ik ) {
00540         count += buckets[ik]->size();
00541       }
00542 
00543       std::vector<Entity*> entities( count );
00544 
00545       std::vector<Entity*>::iterator j = entities.begin();
00546 
00547       for ( size_t ik = bk ; ik != ek ; ++ik ) {
00548         Bucket & b = * buckets[ik];
00549         const unsigned n = b.size();
00550         for ( unsigned i = 0 ; i < n ; ++i , ++j ) {
00551           *j = & b[i] ;
00552         }
00553       }
00554 
00555       std::sort( entities.begin() , entities.end() , EntityLess() );
00556 
00557       j = entities.begin();
00558 
00559       bool change_this_family = false ;
00560 
00561       for ( size_t ik = bk ; ik != ek ; ++ik ) {
00562         Bucket & b = * buckets[ik];
00563         const unsigned n = b.size();
00564         for ( unsigned i = 0 ; i < n ; ++i , ++j ) {
00565           Entity * const current = & b[i] ;
00566 
00567           if ( current != *j ) {
00568 
00569             if ( current ) {
00570               // Move current entity to the vacant spot
00571               copy_fields( *ik_vacant , ie_vacant , b, i );
00572               m_entity_repo.change_entity_bucket(*ik_vacant, *current, ie_vacant);
00573               ik_vacant->m_bucketImpl.replace_entity( ie_vacant , current ) ;
00574             }
00575 
00576             // Set the vacant spot to where the required entity is now.
00577             ik_vacant = & ((*j)->bucket()) ;
00578             ie_vacant = (*j)->bucket_ordinal() ;
00579             ik_vacant->m_bucketImpl.replace_entity( ie_vacant , NULL ) ;
00580 
00581             // Move required entity to the required spot
00582             copy_fields( b, i, *ik_vacant , ie_vacant );
00583             m_entity_repo.change_entity_bucket( b, **j, i);
00584             b.m_bucketImpl.replace_entity( i, *j );
00585 
00586             change_this_family = true ;
00587           }
00588 
00589           // Once a change has occured then need to propagate the
00590           // relocation for the remainder of the family.
00591           // This allows the propagation to be performed once per
00592           // entity as opposed to both times the entity is moved.
00593 
00594           if ( change_this_family ) { internal_propagate_relocation( **j ); }
00595         }
00596       }
00597 
00598       if ( b_scratch ) {
00599         // Created a last bucket, now have to destroy it.
00600         destroy_bucket( entity_rank , b_scratch );
00601         --ek ;
00602       }
00603     }
00604   }
00605 }
00606 
00607 //----------------------------------------------------------------------
00608 
00609 void BucketRepository::remove_entity( Bucket * k , unsigned i )
00610 {
00611 
00612   if ( k == m_nil_bucket) {
00613     throw std::logic_error("BucketRepository::remove_entity: Cannot remove entity from nil_bucket");
00614   }
00615 
00616   const unsigned entity_rank = k->entity_rank();
00617 
00618   // Last bucket in the family of buckets with the same parts.
00619   // The last bucket is the only non-full bucket in the family.
00620 
00621   Bucket * const last = k->m_bucketImpl.last_bucket_in_family();
00622 
00623   // Fill in the gap if it is not the last entity being removed
00624 
00625   if ( last != k || k->size() != i + 1 ) {
00626 
00627     // Copy last entity in last bucket to bucket *k slot i
00628 
00629     Entity & entity = (*last)[ last->size() - 1 ];
00630 
00631     copy_fields( *k , i , *last , last->size() - 1 );
00632 
00633     k->m_bucketImpl.replace_entity(i, & entity ) ;
00634     m_entity_repo.change_entity_bucket( *k, entity, i);
00635 
00636     // Entity field data has relocated
00637 
00638     internal_propagate_relocation( entity );
00639   }
00640 
00641   last->m_bucketImpl.decrement_size();
00642 
00643   last->m_bucketImpl.replace_entity( last->size() , NULL ) ;
00644 
00645   if ( 0 == last->size() ) {
00646     destroy_bucket( entity_rank , last );
00647   }
00648 }
00649 
00650 //----------------------------------------------------------------------
00651 
00652 void BucketRepository::internal_propagate_relocation( Entity & entity )
00653 {
00654   const unsigned etype = entity.entity_rank();
00655   PairIterRelation rel = entity.relations();
00656 
00657   for ( ; ! rel.empty() ; ++rel ) {
00658     const unsigned rel_type = rel->entity_rank();
00659     if ( rel_type < etype ) {
00660       Entity & e_to = * rel->entity();
00661 
00662       set_field_relations( entity, e_to, rel->identifier() );
00663     }
00664     else if ( etype < rel_type ) {
00665       Entity & e_from = * rel->entity();
00666 
00667       set_field_relations( e_from, entity, rel->identifier() );
00668     }
00669   }
00670 }
00671 
00672 
00673 } // namespace impl
00674 } // namespace mesh
00675 } // namespace stk
00676 
00677 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends