Sierra Toolkit Version of the Day
BulkDataParallelVerify.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 
00014 #include <set>
00015 #include <stdexcept>
00016 #include <iostream>
00017 #include <sstream>
00018 #include <algorithm>
00019 
00020 #include <stk_util/parallel/ParallelComm.hpp>
00021 #include <stk_util/parallel/ParallelReduce.hpp>
00022 
00023 #include <stk_mesh/base/Ghosting.hpp>
00024 #include <stk_mesh/base/BulkData.hpp>
00025 #include <stk_mesh/base/MetaData.hpp>
00026 #include <stk_mesh/base/FieldData.hpp>
00027 #include <stk_mesh/base/EntityComm.hpp>
00028 #include <stk_mesh/base/Comm.hpp>
00029 
00030 namespace stk {
00031 namespace mesh {
00032 
00033 namespace {
00034 
00035 bool verify_parallel_attributes( BulkData & M , std::ostream & error_log );
00036 
00037 void pack_owned_verify( CommAll & all , const BulkData & mesh );
00038 
00039 bool unpack_not_owned_verify( CommAll & comm_all ,
00040                               const BulkData & mesh ,
00041                               std::ostream & error_log );
00042 
00043 }
00044 
00045 bool comm_mesh_verify_parallel_consistency(
00046   BulkData & M , std::ostream & error_log )
00047 {
00048   int result = 1 ;
00049 
00050   // Verify consistency of parallel attributes
00051 
00052   result = verify_parallel_attributes( M , error_log );
00053 
00054   all_reduce( M.parallel() , ReduceMin<1>( & result ) );
00055 
00056   // Verify entities against owner.
00057 
00058   if ( result ) {
00059     CommAll all( M.parallel() );
00060 
00061     pack_owned_verify( all , M );
00062 
00063     all.allocate_buffers( all.parallel_size() / 4 );
00064 
00065     pack_owned_verify( all , M );
00066 
00067     all.communicate();
00068 
00069     result = unpack_not_owned_verify( all , M , error_log );
00070 
00071     all_reduce( M.parallel() , ReduceMin<1>( & result ) );
00072   }
00073 
00074   return result == 1 ;
00075 }
00076 
00077 namespace {
00078 
00079 bool ordered_comm( const Entity & entity )
00080 {
00081   const PairIterEntityComm ec = entity.comm();
00082   const size_t n = ec.size();
00083   for ( size_t i = 1 ; i < n ; ++i ) {
00084     if ( ! ( ec[i-1] < ec[i] ) ) {
00085       return false ;
00086     }
00087   }
00088   return true ;
00089 }
00090 
00091 bool verify_parallel_attributes( BulkData & M , std::ostream & error_log )
00092 {
00093   bool result = true ;
00094 
00095   const MetaData & S = M.mesh_meta_data();
00096   Part & owns_part = S.locally_owned_part();
00097   Part & shares_part = S.globally_shared_part();
00098 
00099   const unsigned p_rank = M.parallel_rank();
00100 
00101   const size_t EntityRankEnd = M.mesh_meta_data().entity_rank_count();
00102 
00103   size_t comm_count = 0 ;
00104 
00105   for ( size_t itype = 0 ; itype < EntityRankEnd ; ++itype ) {
00106     const std::vector< Bucket * > & all_buckets = M.buckets( itype );
00107 
00108     const std::vector<Bucket*>::const_iterator i_end = all_buckets.end();
00109           std::vector<Bucket*>::const_iterator i     = all_buckets.begin();
00110 
00111     while ( i != i_end ) {
00112       Bucket & bucket = **i ; ++i ;
00113 
00114       const bool has_owns_part   = has_superset( bucket , owns_part );
00115       const bool has_shares_part = has_superset( bucket , shares_part );
00116 
00117       const Bucket::iterator j_end = bucket.end();
00118             Bucket::iterator j     = bucket.begin();
00119 
00120       while ( j != j_end ) {
00121         Entity & entity = *j ; ++j ;
00122 
00123         bool this_result = true ;
00124 
00125         const unsigned p_owner    = entity.owner_rank();
00126         const bool     ordered    = ordered_comm( entity );
00127         const bool     shares     = in_shared( entity );
00128         const bool     recv_ghost = in_receive_ghost( entity );
00129         const bool     send_ghost = in_send_ghost( entity );
00130         const bool     owned_closure = in_owned_closure( entity , p_rank );
00131 
00132         if ( ! ordered ) {
00133           error_log << "Problem is unordered" << std::endl;
00134           this_result = false ;
00135         }
00136 
00137         // Owner consistency:
00138 
00139         if (   has_owns_part && p_owner != p_rank ) {
00140           error_log << "problem is owner-consistency check 1: "
00141                     << "has_owns_part: " << has_owns_part << ", "
00142                     << "p_owner: " << p_owner << ", "
00143                     << "p_rank: " << p_rank << std::endl;
00144           this_result = false ;
00145         }
00146 
00147         if ( ! has_owns_part && p_owner == p_rank ) {
00148           error_log << "problem is owner-consistency check 2: "
00149                     << "has_owns_part: " << has_owns_part << ", "
00150                     << "p_owner: " << p_owner << ", "
00151                     << "p_rank: " << p_rank << std::endl;
00152           this_result = false ;
00153         }
00154 
00155         if ( has_shares_part != shares ) {
00156           error_log << "problem is owner-consistency check 3: "
00157                     << "has_shares_part: " << has_shares_part << ", "
00158                     << "shares: " << shares << std::endl;
00159           this_result = false ;
00160         }
00161 
00162         // Definition of 'closure'
00163 
00164         if ( ( has_owns_part || has_shares_part ) != owned_closure ) {
00165           error_log << "problem is closure check 1: "
00166                     << "has_owns_part: " << has_owns_part << ", "
00167                     << "has_shares_part: " << has_shares_part << ", "
00168                     << "owned_closure: " << owned_closure << std::endl;
00169           this_result = false ;
00170         }
00171 
00172         // Must be either owned_closure or recv_ghost but not both.
00173 
00174         if (   owned_closure &&   recv_ghost ) {
00175           error_log << "problem is recv ghost check 1: "
00176                     << "owned_closure: " << owned_closure << ", "
00177                     << "recv_ghost: " << recv_ghost << std::endl;
00178           this_result = false ;
00179         }
00180         if ( ! owned_closure && ! recv_ghost ) {
00181           error_log << "problem is recv ghost check 2: "
00182                     << "owned_closure: " << owned_closure << ", "
00183                     << "recv_ghost: " << recv_ghost << std::endl;
00184           this_result = false ;
00185         }
00186 
00187         // If sending as a ghost then I must own it
00188 
00189         if ( ! has_owns_part && send_ghost ) {
00190           error_log << "problem is send ghost check 1: "
00191                     << "has_owns_part: " << has_owns_part << ", "
00192                     << "send_ghost: " << send_ghost << std::endl;
00193           this_result = false ;
00194         }
00195 
00196         // If shared then I am owner or owner is in the shared list
00197 
00198         if ( shares && p_owner != p_rank ) {
00199           PairIterEntityComm ip = entity.sharing();
00200           for ( ; ! ip.empty() && p_owner != ip->proc ; ++ip );
00201           if ( ip.empty() ) {
00202             error_log << "problem is shared check 1" << std::endl;
00203             this_result = false ;
00204           }
00205         }
00206 
00207         if ( shares || recv_ghost || send_ghost ) { ++comm_count ; }
00208 
00209         if ( ! this_result ) {
00210           result = false ;
00211           error_log << "P" << M.parallel_rank() << ": " ;
00212           print_entity_key( error_log , M.mesh_meta_data(), entity.key() );
00213           error_log << " ERROR: owner(" << p_owner
00214                     << ") owns(" << has_owns_part
00215                     << ") shares(" << has_shares_part
00216                     << ") owned_closure(" << owned_closure
00217                     << ") recv_ghost(" << recv_ghost
00218                     << ") send_ghost(" << send_ghost
00219                     << ") comm(" ;
00220           PairIterEntityComm ip = entity.comm();
00221           for ( ; ! ip.empty() ; ++ip ) {
00222             error_log << " " << ip->ghost_id << ":" << ip->proc ;
00223           }
00224           error_log << " )" << std::endl ;
00225         }
00226       }
00227     }
00228   }
00229 
00230   for ( std::vector<Entity*>::const_iterator
00231         i =  M.entity_comm().begin() ;
00232         i != M.entity_comm().end() ; ++i ) {
00233 
00234     const PairIterEntityComm ec = (*i)->comm();
00235 
00236     if ( ec.empty() ) {
00237       print_entity_key( error_log , M.mesh_meta_data(), (*i)->key() );
00238       error_log << " ERROR: in entity_comm but has no comm info" << std::endl ;
00239       result = false ;
00240     }
00241   }
00242 
00243   if ( M.entity_comm().size() != comm_count ) {
00244     error_log << " ERROR: entity_comm.size() = " << M.entity_comm().size();
00245     error_log << " != " << comm_count << " = entities with comm info" ;
00246     error_log << std::endl ;
00247     result = false ;
00248   }
00249 
00250   return result ;
00251 }
00252 
00253 //----------------------------------------------------------------------------
00254 // Packing my owned entities.
00255 
00256 void insert( std::vector<unsigned> & vec , unsigned val )
00257 {
00258   std::vector<unsigned>::iterator j =
00259     std::lower_bound( vec.begin() , vec.end() , val );
00260   if ( j == vec.end() || *j != val ) {
00261     vec.insert( j , val );
00262   }
00263 }
00264 
00265 void pack_owned_verify( CommAll & all , const BulkData & mesh )
00266 {
00267   const std::vector<Entity*> & entity_comm = mesh.entity_comm();
00268   const unsigned p_rank = all.parallel_rank();
00269 
00270   for ( std::vector<Entity*>::const_iterator
00271         i = entity_comm.begin() ; i != entity_comm.end() ; ++i ) {
00272 
00273     Entity & entity = **i ;
00274 
00275     if ( entity.owner_rank() == p_rank ) {
00276 
00277       std::vector<unsigned> share_proc ;
00278       std::vector<unsigned> ghost_proc ;
00279 
00280       const PairIterEntityComm comm = entity.comm();
00281 
00282       for ( size_t j = 0 ; j < comm.size() ; ++j ) {
00283         if ( comm[j].ghost_id == 0 ) {
00284           // Will be ordered by proc
00285           share_proc.push_back( comm[j].proc );
00286         }
00287         else {
00288           // No guarantee of ordering by proc
00289           insert( ghost_proc , comm[j].proc );
00290         }
00291       }
00292 
00293       const unsigned share_count = share_proc.size();
00294 
00295       for ( size_t j = 0 ; j < share_proc.size() ; ++j ) {
00296 
00297         // Sharing process, send sharing process list
00298 
00299         const unsigned p = share_proc[j] ;
00300 
00301         CommBuffer & buf = all.send_buffer( p );
00302 
00303         pack_entity_info( buf , entity );
00304 
00305         buf.pack<unsigned>( share_count );
00306 
00307         // Pack what the receiver should have:
00308         // My list, remove receiver, add myself
00309         size_t k = 0 ;
00310         for ( ; k < share_count && share_proc[k] < p_rank ; ++k ) {
00311           if ( k != j ) { buf.pack<unsigned>( share_proc[k] ); }
00312         }
00313         buf.pack<unsigned>( p_rank );
00314         for ( ; k < share_count ; ++k ) {
00315           if ( k != j ) { buf.pack<unsigned>( share_proc[k] ); }
00316         }
00317       }
00318 
00319       for ( size_t j = 0 ; j < ghost_proc.size() ; ++j ) {
00320         const unsigned p = ghost_proc[j] ;
00321 
00322         CommBuffer & buf = all.send_buffer( p );
00323 
00324         pack_entity_info( buf , entity );
00325 
00326         // What ghost subsets go to this process?
00327         unsigned count = 0 ;
00328         for ( size_t k = 0 ; k < comm.size() ; ++k ) {
00329           if ( comm[k].ghost_id != 0 && comm[k].proc == p ) {
00330             ++count ;
00331           }
00332         }
00333         buf.pack<unsigned>( count );
00334         for ( size_t k = 0 ; k < comm.size() ; ++k ) {
00335           if ( comm[k].ghost_id != 0 && comm[k].proc == p ) {
00336             buf.pack<unsigned>( comm[k].ghost_id );
00337           }
00338         }
00339       }
00340     }
00341   }
00342 }
00343 
00344 //----------------------------------------------------------------------------
00345 // Unpacking all of my not-owned entities.
00346 
00347 bool unpack_not_owned_verify( CommAll & comm_all ,
00348                               const BulkData & mesh ,
00349                               std::ostream & error_log )
00350 {
00351   const MetaData & meta = mesh.mesh_meta_data();
00352   Part * const       owns_part   = & meta.locally_owned_part();
00353   Part * const       shares_part = & meta.globally_shared_part();
00354   const PartVector & mesh_parts  = meta.get_parts();
00355   const unsigned     p_rank = mesh.parallel_rank();
00356   const std::vector<Entity*> & entity_comm = mesh.entity_comm();
00357 
00358   bool result = true ;
00359 
00360   EntityKey             recv_entity_key ;
00361   unsigned              recv_owner_rank = 0 ;
00362   unsigned              recv_comm_count = 0 ;
00363   std::vector<Part*>    recv_parts ;
00364   std::vector<Relation> recv_relations ;
00365   std::vector<unsigned> recv_comm ;
00366 
00367   for ( std::vector<Entity*>::const_iterator
00368         i = entity_comm.begin() ; i != entity_comm.end() ; ++i ) {
00369 
00370     Entity & entity = **i ;
00371 
00372     if ( entity.owner_rank() != p_rank ) {
00373 
00374       const Bucket & bucket = entity.bucket();
00375 
00376       std::pair<const unsigned *,const unsigned *>
00377         part_ordinals = bucket.superset_part_ordinals();
00378 
00379       CommBuffer & buf = comm_all.recv_buffer( entity.owner_rank() );
00380 
00381       unpack_entity_info( buf , mesh ,
00382                           recv_entity_key , recv_owner_rank ,
00383                           recv_parts , recv_relations );
00384 
00385       recv_comm_count = 0 ;
00386       buf.unpack<unsigned>( recv_comm_count );
00387       recv_comm.resize( recv_comm_count );
00388       buf.unpack<unsigned>( & recv_comm[0] , recv_comm_count );
00389 
00390       // Match key and owner
00391 
00392       const bool bad_key = entity.key()        != recv_entity_key ;
00393       const bool bad_own = entity.owner_rank() != recv_owner_rank ;
00394       bool bad_part = false ;
00395       bool bad_rel  = false ;
00396       bool bad_comm = false ;
00397 
00398       // Compare communication information:
00399 
00400       if ( ! bad_key && ! bad_own ) {
00401         const PairIterEntityComm ec = entity.comm();
00402         const unsigned ec_size = ec.size();
00403         bad_comm = ec_size != recv_comm.size();
00404         if ( ! bad_comm ) {
00405           size_t j = 0 ;
00406           if ( in_shared( entity ) ) {
00407             for ( ; j < ec_size &&
00408                     ec[j].ghost_id == 0 &&
00409                     ec[j].proc   == recv_comm[j] ; ++j );
00410             bad_comm = j != ec_size ;
00411           }
00412           else {
00413             for ( ; j < ec_size &&
00414                     ec[j].ghost_id == recv_comm[j] &&
00415                     ec[j].proc   == entity.owner_rank() ; ++j );
00416             bad_comm = j != ec_size ;
00417           }
00418         }
00419       }
00420 
00421       // Compare everything but the owns part and uses part
00422 
00423       if ( ! bad_key && ! bad_own && ! bad_comm ) {
00424 
00425         const unsigned * k = part_ordinals.first ;
00426 
00427         std::vector<Part*>::iterator ip = recv_parts.begin();
00428 
00429         for ( ; ! bad_part && ip != recv_parts.end() ; ++ip ) {
00430           if ( owns_part != *ip ) {
00431             if ( shares_part != *ip ) {
00432               // All not-owned and not-shares parts must match:
00433               bad_part = k == part_ordinals.second ||
00434                          (*ip)->mesh_meta_data_ordinal() != *k ;
00435               ++k ;
00436             }
00437             else if ( k != part_ordinals.second &&
00438                      *k == shares_part->mesh_meta_data_ordinal() ) {
00439               // shares-part matches
00440               ++k ;
00441             }
00442           }
00443         }
00444       }
00445 
00446       // Compare the closure relations:
00447       if ( ! bad_key && ! bad_own && ! bad_comm && ! bad_part ) {
00448 
00449         PairIterRelation ir = entity.relations();
00450 
00451         std::vector<Relation>::iterator jr = recv_relations.begin() ;
00452 
00453         for ( ; ! bad_rel && jr != recv_relations.end() &&
00454                 jr->entity_rank() < entity.entity_rank() ; ++jr , ++ir ) {
00455           bad_rel = ir.empty() || *jr != *ir ;
00456         }
00457       }
00458 
00459       if ( bad_key || bad_own || bad_comm || bad_part || bad_rel ) {
00460         error_log << "P" << p_rank << ": " ;
00461         print_entity_key( error_log , meta, entity.key() );
00462         error_log << " owner(" << entity.owner_rank() << ")" ;
00463 
00464         if ( bad_key || bad_own ) {
00465           error_log << " != received " ;
00466           print_entity_key( error_log , meta, recv_entity_key );
00467           error_log << " owner(" << recv_owner_rank
00468                     << ")" << std::endl ;
00469         }
00470         else if ( bad_comm ) {
00471           const PairIterEntityComm ec = entity.comm();
00472           if ( in_shared( entity ) ) {
00473             error_log << " sharing(" ;
00474             for ( size_t j = 0 ; j < ec.size() &&
00475                                  ec[j].ghost_id == 0 ; ++j ) {
00476               error_log << " " << ec[j].proc ;
00477             }
00478             error_log << " ) != received sharing(" ;
00479             for ( size_t j = 0 ; j < recv_comm.size() ; ++j ) {
00480               error_log << " " << recv_comm[j] ;
00481             }
00482             error_log << " )" << std::endl ;
00483           }
00484           else {
00485             error_log << " ghosting(" ;
00486             for ( size_t j = 0 ; j < ec.size() ; ++j ) {
00487               error_log << " (g" << ec[j].ghost_id ;
00488               error_log << ",p" << ec[j].proc ;
00489               error_log << ")" ;
00490             }
00491             error_log << " ) != received ghosting(" ;
00492             for ( size_t j = 0 ; j < recv_comm.size() ; ++j ) {
00493               error_log << " (g" << recv_comm[j] ;
00494               error_log << ",p" << entity.owner_rank();
00495               error_log << ")" ;
00496             }
00497             error_log << " )" << std::endl ;
00498           }
00499         }
00500         else if ( bad_part ) {
00501           error_log << " Parts( " ;
00502 
00503           for ( const unsigned * k = part_ordinals.first ;
00504                                  k < part_ordinals.second ; ++k ) {
00505             error_log << " \"" << mesh_parts[ *k ]->name() << "\"" ;
00506           }
00507           error_log << " ) != received Parts( " ;
00508 
00509           for ( std::vector<Part*>::iterator
00510                 ip =  recv_parts.begin();
00511                 ip != recv_parts.end() ; ++ip ) {
00512             error_log << " \"" << (*ip)->name() << "\"" ;
00513           }
00514           error_log << " )" << std::endl ;
00515         }
00516         else if ( bad_rel ) {
00517           error_log << " Relations(" ;
00518           PairIterRelation ir = entity.relations();
00519           for ( ; ! ir.empty() &&
00520                   ir->entity_rank() < entity.entity_rank() ; ++ir ) {
00521             error_log << " " << *ir ;
00522           }
00523           error_log << " ) != received Relations(" ;
00524           std::vector<Relation>::iterator jr = recv_relations.begin() ;
00525           for ( ; jr != recv_relations.end() &&
00526                   jr->entity_rank() < entity.entity_rank() ; ++jr ) {
00527             error_log << " " << *jr ;
00528           }
00529           error_log << " )" << std::endl ;
00530         }
00531         result = false ;
00532       }
00533     }
00534   }
00535 
00536   return result ;
00537 }
00538 
00539 } // namespace<>
00540 
00541 } // namespace mesh
00542 } // namespace stk
00543 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends