Sierra Toolkit Version of the Day
Transaction.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 
00010 #include <stdexcept>
00011 
00012 
00013 
00014 #include <stk_mesh/base/Entity.hpp>
00015 #include <stk_mesh/base/Bucket.hpp>
00016 #include <stk_mesh/base/BulkData.hpp>
00017 #include <stk_mesh/base/Transaction.hpp>
00018 
00019 namespace stk {
00020 namespace mesh {
00021 
00022 
00023 void print_bucket_list ( const BucketList &bl , std::ostream &os )
00024 {
00025   BucketList::const_iterator  cur_bucket = bl.begin();
00026   while ( cur_bucket != bl.end() )
00027   {
00028     os << "Bucket key: ";
00029 //This is bad code, no longer works. Re-visit this if/when the
00030 //Transaction class is ever resurrected.
00031 //    for ( unsigned i = 0 ; i <= (*cur_bucket)->m_key[0] ; i++ )
00032 //      os << (*cur_bucket)->m_key[i] << " ";
00033 //    os << "\n";
00034 //    os << "Entities: ";
00035 //    for ( unsigned i = 0 ; i != (*cur_bucket)->m_size ; i++ )
00036 //      os << (*cur_bucket)->m_entities[i]->identifier() << " ";
00037 //    os << "\n-------------------\n";
00038     cur_bucket++;
00039   }
00040 }
00041 
00046 #if 0
00047 
00048 void Transaction::print_transaction ( unsigned type , std::ostream &os ) const
00049 {
00050   os << "Transaction details for type = " << type << "\n";
00051   os << "-=-=- Proc " << m_bulk_data.parallel_rank() << " -=-=-\n";
00052   print_proc_transaction ( type , os );
00053   os << std::endl;
00054 }
00055 
00056 void Transaction::print_proc_transaction ( unsigned type , std::ostream &os ) const
00057 {
00058   os << "  Modified has " << m_modified[type].size() << " buckets\n"
00059      << "  Nowhere has " << m_deleted[type].size() << " buckets\n"
00060      << "  Inserted has " << m_inserted[type].size() << " buckets\n";
00061   os << " Modified buckets:\n";
00062   print_bucket_list ( m_modified[type] , os );
00063   os << " Nowhere buckets:\n";
00064   print_bucket_list ( m_deleted[type] , os );
00065   os << " Inserted buckets:\n";
00066   print_bucket_list ( m_inserted[type] , os );
00067 }
00068 
00069 std::ostream & Transaction::print_stream ( std::ostream &os ) const
00070 {
00071   for ( unsigned i = 0 ; i != m_modified.size() ; i++ )
00072     print_transaction ( i , os );
00073   return os;
00074 }
00075 
00076 Transaction::Transaction ( BulkData &bd , TransactionType type ) : m_transaction_type(type) ,
00077                                                                    m_bulk_data ( bd ) ,
00078                                                                    m_modified ( ) ,
00079                                                                    m_deleted ( ) ,
00080                                                                    m_inserted ( )
00081 {
00082   allocate_bucket_lists ();
00083 }
00084 
00085 Transaction::~Transaction ()
00086 {
00087   reset ();
00088 }
00089 
00090 
00091 
00092 // This allocation works on the assumption that the entity types are
00093 // packed and enumerated from zero.  This assumption is currently safe
00094 // since bulk data makes the same assumption.  Should this ever
00095 // change in bulk data, the same change must occur here.
00096 void Transaction::allocate_bucket_lists ()
00097 {
00098   m_modified.resize ( m_bulk_data.mesh_meta_data().entity_rank_count() );
00099   m_deleted.resize ( m_bulk_data.mesh_meta_data().entity_rank_count() );
00100   m_inserted.resize ( m_bulk_data.mesh_meta_data().entity_rank_count() );
00101 }
00102 
00103 
00104 // This method will place entity e in the modified buckets.  Unlike
00105 // modify_entity, this will not add the from-entity relations to the
00106 // modified bucket.  This method is invoked on the to-entity of a new
00107 // or changed relation.  If the entity is already in a transaction
00108 // bucket, this method returns with no change
00109 void Transaction::modify_sole_entity ( Entity &e )
00110 {
00111   // If no bucket is specified yet, then the entity is inserted and
00112   // should be ignored
00113   if ( e.m_bucket == 0 ) return;
00114 
00115   // Ignore spurious calls to internal_change_entity_parts
00116   if ( e.m_trans_bucket != 0 ) return;
00117 
00118   add_parts_to_partset ( e , m_modified_parts );
00119 
00120   // If this is not an incremental transaction, ignore
00121   if ( m_transaction_type != INCREMENTAL ) return;
00122 
00123   Bucket *transaction_bucket = get_unfilled_transaction_bucket ( e , m_modified[e.entity_rank()] , MODIFIED );
00124 
00125   add_entity_to_transaction_bucket ( e , transaction_bucket );
00126 }
00127 
00128 // This method will add e to the modified bucket and every entity for
00129 // which e is directly related to.  This method is invoked an all
00130 // modification other than the to-entity of a new or modified
00131 // relation.  If the entity is already in a transaction bucket, this
00132 // method returns with no change.
00133 void Transaction::modify_entity ( Entity &e )
00134 {
00135 
00136   // If no bucket is specified yet, then the entity is inserted and
00137   // should be ignored
00138   if ( e.m_bucket == 0 ) return;
00139 
00140   // Ignore spurious calls to internal_change_entity_parts
00141   if ( e.m_trans_bucket != 0 ) return;
00142 
00143   add_parts_to_partset ( e , m_modified_parts );
00144 
00145   // If this is not an incremental transaction, ignore
00146   if ( m_transaction_type != INCREMENTAL ) return;
00147 
00148   Bucket *transaction_bucket = get_unfilled_transaction_bucket ( e , m_modified[e.entity_rank()] , MODIFIED );
00149 
00150   add_entity_to_transaction_bucket ( e , transaction_bucket );
00151 
00152   PairIterRelation current_relation = e.relations();
00153   while ( current_relation.first != current_relation.second )
00154   {
00155     if ( current_relation->entity_rank() > e.entity_rank() )
00156       modify_sole_entity ( *(current_relation->entity()) );
00157     current_relation++;
00158   }
00159 }
00160 
00161 // If an entity is removed from this process, it is placed in the
00162 // deleted bucket.  If the entity is in another transaction bucket, it
00163 // is moved to the deleted bucket and the corresponding parts the
00164 // entity is a member of is moved along with it
00165 void Transaction::delete_entity ( Entity &e )
00166 {
00167   add_parts_to_partset ( e , m_deleted_parts );
00168 
00169   // Determine if entity has already been deleted after insert
00170   // If so, return
00171   if ( m_to_delete.find ( &e ) != m_to_delete.end () )
00172     return;
00173 
00174   // Mark for deletion if the transaction type is BULK
00175   if ( m_transaction_type == BULK )
00176     m_to_delete.insert ( &e );
00177 
00178   // If this is not an incremental transaction, ignore
00179   if ( m_transaction_type != INCREMENTAL ) return;
00180 
00181   if ( e.m_trans_bucket )
00182   {
00183     if ( e.transaction_bucket()->transaction_state() == DELETED ) return;
00184     if ( e.transaction_bucket()->transaction_state() == MODIFIED )
00185     {
00186       swap_entity_between_transaction_buckets ( e , m_modified[e.entity_rank()] , m_deleted[e.entity_rank()] , DELETED );
00187       return;
00188     }
00189     if ( e.transaction_bucket()->transaction_state() == INSERTED )
00190     {
00191       remove_entity_from_bucket ( e , m_inserted[e.entity_rank()]  );
00192       // Need to mark this for deletion at reset since it will not be
00193       // stored anywhere
00194       m_to_delete.insert ( &e );
00195       return;
00196     }
00197   }
00198 
00199   Bucket *transaction_bucket = get_unfilled_transaction_bucket ( e , m_deleted[e.entity_rank()] , DELETED );
00200   add_entity_to_transaction_bucket ( e , transaction_bucket );
00201 }
00202 
00203 // If an entity is inserted into the mesh, it is placed in the insert
00204 // bucket.  If it is a member of another bucket, this function does
00205 // nothing.  It should be an error to be in another bucket and this
00206 // should be caught elsewhere.
00207 void Transaction::insert_entity ( Entity &e )
00208 {
00209 
00210   if ( e.m_trans_bucket != 0 ) return;
00211 
00212   add_parts_to_partset ( e , m_inserted_parts );
00213 
00214   // If this is not an incremental transaction, ignore
00215   if ( m_transaction_type != INCREMENTAL ) return;
00216 
00217   Bucket *transaction_bucket = get_unfilled_transaction_bucket ( e , m_inserted[e.entity_rank()] , INSERTED );
00218   add_entity_to_transaction_bucket ( e , transaction_bucket );
00219 }
00220 
00221 // Upon modification_begin() in bulk data, the transaction purges the
00222 // transaction buckets.  This function simply deallocates the bucket
00223 // and removes entities from the transaction bucket.
00224 void Transaction::purge_map ( BucketListByType &buckets )
00225 {
00226   BucketListByType::iterator cur_type = buckets.begin();
00227   while ( cur_type != buckets.end() )
00228   {
00229     BucketList::iterator cur_bucket = cur_type->begin();
00230     while ( cur_bucket != cur_type->end() )
00231     {
00232       BucketIterator  cur_entity = (*cur_bucket)->begin();
00233       while ( cur_entity != (*cur_bucket)->end() )
00234       {
00235         cur_entity->m_trans_bucket = NULL;
00236         cur_entity++;
00237       }
00238       Bucket::destroy_bucket ( *cur_bucket );
00239       cur_bucket++;
00240     }
00241     cur_type->clear();
00242     cur_type++;
00243   }
00244 
00245 }
00246 
00247 // This method will purge buckets and delete entities from memory.
00248 // This method uses the internal_destroy_entire_bucket method in
00249 // BulkData which does not, in turn, call the delete_entity
00250 // transaction function.
00251 /*
00252 void Transaction::purge_and_erase_map ( BucketListByType &buckets )
00253 {
00254   BucketListByType::iterator cur_type = buckets.begin();
00255   while ( cur_type != buckets.end() )
00256   {
00257     BucketList::iterator cur_bucket = cur_type->begin();
00258     while ( cur_bucket != cur_type->end() )
00259     {
00260       m_bulk_data.internal_destroy_entire_bucket ( *cur_bucket );
00261       cur_bucket++;
00262     }
00263     cur_type->clear();
00264     cur_type++;
00265   }
00266 }
00267 
00268 void Transaction::flush_deletes ()
00269 {
00270   for ( std::set<Entity *>::iterator  cur_del_entity = m_to_delete.begin() ; cur_del_entity != m_to_delete.end() ; cur_del_entity++ )
00271     m_bulk_data.internal_expunge_entity ( *cur_del_entity );
00272   m_to_delete.clear ();
00273 }
00274 */
00275 
00276 
00277 void Transaction::flush()
00278 {
00279   purge_map ( m_modified );
00280   purge_map ( m_inserted );
00281   purge_map ( m_deleted );
00282 
00283   m_modified_parts.clear();
00284   m_deleted_parts.clear();
00285   m_inserted_parts.clear();
00286 }
00287 
00288 // Explicity purge and erase memory as needed.
00289 void Transaction::reset ( TransactionType type )
00290 {
00291   m_transaction_type = type;
00292   flush();
00293 }
00294 
00295 void Transaction::add_parts_to_partset ( Entity &e , PartSet &pl )
00296 {
00297   PartVector  parts;
00298   e.bucket().supersets ( parts );
00299 
00300   for ( PartVector::iterator part_iter = parts.begin(); part_iter != parts.end() ; ++part_iter )
00301     pl.insert ( *part_iter );
00302 
00303 
00304 }
00305 
00306 void Transaction::translate_partset_to_partvector ( const PartSet &in , PartVector &out ) const
00307 {
00308   out.resize ( in.size() );
00309   unsigned i = 0;
00310   for ( PartSet::const_iterator cur_in = in.begin() ; cur_in != in.end() ; cur_in++ )
00311   {
00312     out[i] = *cur_in;
00313     ++i;
00314   }
00315 }
00316 
00317 // The bucket b is assumed to have enough space to add entity e.  This
00318 // is placed on the end of the array and the size is incremented.
00319 void Transaction::add_entity_to_transaction_bucket ( Entity &e , Bucket *b )
00320 {
00321   b->m_entities[b->m_size] = &e;
00322   e.m_trans_bucket = b;
00323   e.m_trans_bucket_ord = b->m_size;
00324   b->m_size++;
00325 }
00326 
00327 // Entity e is removed from ''from'' and placed in ''to''.
00328 void Transaction::swap_entity_between_transaction_buckets ( Entity &e , BucketList &from , BucketList &to , State s )
00329 {
00330   Bucket *to_bucket = get_unfilled_transaction_bucket ( e , to , s );
00331   remove_entity_from_bucket ( e , from );
00332   add_entity_to_transaction_bucket ( e , to_bucket );
00333 }
00334 
00335 
00336 // This is a wrapper around the Bucket::declare_bucket.  Each bucket
00337 // has no field data and has a copy of the key from the current bucket
00338 // the entity is in.
00339 Bucket *Transaction::get_unfilled_transaction_bucket ( const unsigned * const key , EntityRank type , BucketList &buckets , State s )
00340 {
00341   Bucket *new_bucket = Bucket::declare_bucket ( m_bulk_data ,
00342                                                 type ,
00343                                                 key[0] - 1 ,
00344                                                 key+1 ,
00345                                                 m_bulk_data.bucket_capacity() ,
00346                                                 std::vector<FieldBase *> () ,
00347                                                 buckets );
00348 
00349   new_bucket->m_transaction_state = s;
00350 
00351   return new_bucket;
00352 }
00353 
00354 
00355 // This code was copied from bulk data and used to remove entities
00356 // from buckets.  In order to remove an entity, an appropriate entity
00357 // must be found to copy into the hole.  This logic will find the
00358 // appropriate bucket which has an entity to copy into the bucket.
00359 void Transaction::remove_entity_from_bucket ( Entity &e , BucketList &buckets )
00360 {
00361   Bucket *k = e.m_trans_bucket;
00362   unsigned i = e.m_trans_bucket_ord;
00363 
00364   Bucket * const first = k->m_key[ *k->m_key ] ? k->m_bucket : k ;
00365   Bucket * const last  = first->m_bucket ;
00366 
00367   // Only move if not the last entity being removed
00368 
00369   if ( last != k || k->m_size != i + 1 ) {
00370 
00371     // Not the same bucket or not the last entity
00372 
00373     // Copy last entity in last to ik slot i
00374 
00375     Entity * const entity = last->m_entities[ last->m_size - 1 ];
00376 
00377     k->m_entities[i]     = entity ;
00378     entity->m_trans_bucket     = k ;
00379     entity->m_trans_bucket_ord = i ;
00380 
00381   }
00382 
00383   --( last->m_size );
00384 
00385   if ( last->m_size != 0 ) {
00386     last->m_entities[ last->m_size ] = NULL ;
00387   }
00388   else {
00389 
00390     // The current 'last' bucket is to be deleted.
00391     // The previous 'last' bucket becomes the
00392     // new 'last' bucket in the family:
00393 
00394     std::vector<Bucket*>::iterator ik = lower_bound(buckets, last->m_key);
00395 
00396     ThrowRequireMsg( ik != buckets.end() && last == *ik,
00397         "Internal failure during removal of entity " << print_entity_key(e) );
00398 
00399     ik = buckets.erase( ik );
00400 
00401     if ( first != last ) { first->m_bucket = *--ik ; }
00402 
00403     Bucket::destroy_bucket( last );
00404   }
00405 
00406   e.m_trans_bucket = NULL;
00407 }
00408 
00409 #endif
00410 
00411 
00412 }
00413 }
00414 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends