|
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 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