Part.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 #include <iostream>
00012 #include <sstream>
00013 #include <algorithm>
00014 
00015 #include <stk_util/util/string_case_compare.hpp>
00016 #include <stk_mesh/base/Part.hpp>
00017 
00018 namespace stk {
00019 namespace mesh {
00020 
00021 //----------------------------------------------------------------------
00022 
00023 Part * find( const PartVector & parts , const std::string & name )
00024 {
00025   PartVector::const_iterator i = parts.begin();
00026 
00027   while ( i != parts.end() && not_equal_case((*i)->name(),name) ) { ++i ; }
00028 
00029   return i != parts.end() ? *i : NULL ;
00030 }
00031 
00032 //----------------------------------------------------------------------
00033 
00034 std::ostream &
00035 print( std::ostream & os , const char * const lead , const Part & p )
00036 {
00037   const PartVector & supersets = p.supersets();
00038   const PartVector & subsets   = p.subsets();
00039   const PartVector & intersection = p.intersection_of();
00040 
00041   std::vector<Part*>::const_iterator i ;
00042 
00043   if ( lead != NULL ) { os << lead ; }
00044   os << "Part[ " ;
00045   os << p.name() ;
00046   os << " , " ;
00047   os << p.mesh_meta_data_ordinal() ;
00048   os << " ] {" ;
00049   os << std::endl ;
00050 
00051   if ( lead != NULL ) { os << lead ; }
00052   os << "  Supersets {" ;
00053   for ( i = supersets.begin() ; i != supersets.end() ; ++i ) {
00054     const std::string & n = (*i)->name() ; os << " " << n ;
00055   }
00056   os << " }" << std::endl ;
00057 
00058   if ( lead != NULL ) { os << lead ; }
00059   os << "  Intersection_Of {" ;
00060   for ( i = intersection.begin() ; i != intersection.end() ; ++i ) {
00061     const std::string & n = (*i)->name() ; os << " " << n ;
00062   }
00063   os << " } }" << std::endl ;
00064 
00065   if ( lead != NULL ) { os << lead ; }
00066   os << "  Subsets {" ;
00067   for ( i = subsets.begin() ; i != subsets.end() ; ++i ) {
00068     const std::string & n = (*i)->name() ; os << " " << n ;
00069   }
00070   os << " }" << std::endl ;
00071 
00072   return os ;
00073 }
00074 
00075 //----------------------------------------------------------------------
00076 
00077 void order( PartVector & v )
00078 {
00079   PartVector::iterator ev = v.end();
00080   PartVector::iterator iv = v.begin();
00081   std::sort( iv , ev , PartLess() );
00082   iv = std::unique( iv , ev );
00083   v.erase( iv , ev );
00084 }
00085 
00086 bool insert( PartVector & v , Part & part )
00087 {
00088   const PartVector::iterator e = v.end();
00089         PartVector::iterator i = v.begin();
00090 
00091   i = std::lower_bound( i , e , part , PartLess() );
00092 
00093   const bool new_member = i == e || *i != & part ;
00094 
00095   if ( new_member ) { Part * const tmp = & part ; v.insert( i , tmp ); }
00096   return new_member ;
00097 }
00098 
00099 void remove( PartVector & v , Part & part )
00100 {
00101   const PartVector::iterator e = v.end();
00102         PartVector::iterator i = v.begin();
00103 
00104   i = std::lower_bound( i , e , part , PartLess() );
00105 
00106   if ( i != e && *i == & part ) { v.erase( i ); }
00107 }
00108 
00109 bool contain( const PartVector & v , const Part & part )
00110 {
00111   const PartVector::const_iterator e = v.end();
00112         PartVector::const_iterator i = v.begin();
00113 
00114   i = std::lower_bound( i , e , part , PartLess() );
00115 
00116   return i != e && *i == & part ;
00117 }
00118 
00119 bool contain( const PartVector & super , const PartVector & sub )
00120 {
00121   bool result = ( ! sub.empty() ) && ( sub.size() <= super.size() );
00122 
00123   if ( result ) {
00124     PartLess comp ;
00125 
00126     const PartVector::const_iterator ev = super.end();
00127           PartVector::const_iterator iv = super.begin();
00128 
00129     const PartVector::const_iterator ep = sub.end();
00130           PartVector::const_iterator ip = sub.begin();
00131 
00132     while ( result && ip != ep ) {
00133       Part * const q = *ip ; ++ip ;
00134       iv = std::lower_bound( iv , ev , q , comp );
00135       result = iv != ev && *iv == q ; 
00136     }
00137   }
00138 
00139   return result ;
00140 }
00141 
00142 size_t intersect( const PartVector & v , const PartVector & p )
00143 {
00144   // Both lists must be sorted, assume v.size() > p.size()
00145 
00146   const PartVector::const_iterator ev = v.end();
00147         PartVector::const_iterator iv = v.begin();
00148 
00149   const PartVector::const_iterator ep = p.end();
00150         PartVector::const_iterator ip = p.begin();
00151 
00152   size_t count = 0 ;
00153 
00154   for ( ; ip != ep && iv != ev ; ++ip ) {
00155     Part * const q = *ip ;
00156     iv = std::lower_bound( iv , ev , q , PartLess() );
00157     if ( iv != ev && *iv == q ) { ++count ; }
00158   }
00159 
00160   return count ;
00161 }
00162 
00163 size_t intersect( const PartVector & v , const PartVector & p , PartVector & r )
00164 {
00165   // Both lists must be sorted, assume v.size() > p.size()
00166 
00167   const PartVector::const_iterator ev = v.end();
00168         PartVector::const_iterator iv = v.begin();
00169 
00170   const PartVector::const_iterator ep = p.end();
00171         PartVector::const_iterator ip = p.begin();
00172 
00173   for ( ; ip != ep && iv != ev ; ++ip ) {
00174     Part * const q = *ip ;
00175     iv = std::lower_bound( iv , ev , q , PartLess() );
00176     if ( iv != ev && *iv == q ) { r.push_back( q ); }
00177   }
00178 
00179   return r.size() ;
00180 }
00181 
00182 bool intersect( const Part & a , const Part & b )
00183 {
00184   const PartVector & a_sub = a.subsets();
00185   const PartVector & b_sub = b.subsets();
00186   return contain( a_sub , b ) ||
00187          contain( b_sub , a ) ||
00188          intersect( b_sub , a_sub );
00189 }
00190 
00191 //----------------------------------------------------------------------
00192 //----------------------------------------------------------------------
00193 
00194 namespace {
00195 
00196 const char * universal_part_name()
00197 {
00198   static const char name[] = "{UNIVERSAL}" ;
00199   return name ;
00200 }
00201 
00202 void append_part_method(
00203   std::string & msg , const Part & part , const char * method )
00204 {
00205   msg.append( "stk::mesh::Part[" );
00206   msg.append( part.name() );
00207   msg.append( "]." );
00208   msg.append( method );
00209 }
00210 
00211 void assert_universal_part( Part & part , const char * method )
00212 {
00213   if ( ! part.supersets().empty() ) {
00214     std::string msg ;
00215     append_part_method( msg , part , method );
00216     msg.append( "(...) FAILED: Only valid for Part[" );
00217     msg.append( universal_part_name() );
00218     msg.append( "]" );
00219     throw std::runtime_error( msg );
00220   }
00221 }
00222 
00223 void assert_contain( Part & superset , Part & subset , const char * method )
00224 {
00225   if ( ! contain( subset.supersets() , superset ) ) {
00226     std::string msg ;
00227     append_part_method( msg , superset , method );
00228     msg.append( "(...) FAILED Requirement that " );
00229     msg.append( "Part[" );
00230     msg.append( subset.name() );
00231     msg.append( "] is a subset" );
00232     throw std::runtime_error(msg);
00233   }
00234 }
00235 
00236 void assert_same_universe( const Part & part ,
00237                            const char * method ,
00238                            const Part & arg_part )
00239 {
00240   const PartVector & a = part.supersets();
00241   const PartVector & b = arg_part.supersets();
00242 
00243   if ( a.empty() || b.empty() || a[0] != b[0] ) {
00244     std::string msg ;
00245     append_part_method( msg , part , method );
00246     msg.append( "(...) FAILED Requirement that Part[" );
00247     msg.append( arg_part.name() );
00248     msg.append( "] are in the same " );
00249     msg.append( universal_part_name() );
00250     throw std::runtime_error(msg);
00251   }
00252 }
00253 
00254 void assert_not_same( const Part & part ,
00255                       const char * method ,
00256                       const Part & arg_part )
00257 {
00258   if ( & part == & arg_part ) {
00259     std::string msg ;
00260     append_part_method( msg , part , method );
00261     msg.append( "(...) FAILED Requirement that Part[" );
00262     msg.append( arg_part.name() );
00263     msg.append( "] is not the same" );
00264     throw std::runtime_error(msg);
00265   }
00266 }
00267 
00268 void assert_not_superset( const Part & part ,
00269                           const char * method ,
00270                           const Part & arg_part )
00271 {
00272   if ( contain( part.supersets() , arg_part ) ) {
00273     std::string msg ;
00274     append_part_method( msg , part , method );
00275     msg.append( "(...) FAILED Requirement that Part[" );
00276     msg.append( arg_part.name() );
00277     msg.append( "] is not a superset" );
00278     throw std::runtime_error(msg);
00279   }
00280 }
00281 
00282 void assert_rank_ordering( const Part & superset ,
00283                            const char * method ,
00284                            const Part & subset )
00285 {
00286   if ( superset.primary_entity_type() < subset.primary_entity_type() ) {
00287     std::ostringstream msg ;
00288     msg << "stk::mesh::Part[ " << superset.name();
00289     msg << " , rank(" << superset.primary_entity_type();
00290     msg << ") ]." << method ;
00291     msg << "( Part[ " << subset.name();
00292     msg << " , rank(" << subset.primary_entity_type();
00293     msg << ") ] ) FAILED Rank ordering requirement" ;
00294     throw std::runtime_error( msg.str() ); 
00295   }
00296 }
00297 
00298 }
00299 
00300 Part::~Part()
00301 {
00302   // If I am the universal part then I need to delete my subsets:
00303   try {
00304     if ( m_supersets.empty() && this == m_subsets[0] ) {
00305       PartVector::iterator i = m_subsets.begin();
00306       for ( ++i ; i != m_subsets.end() ; ++i ) {
00307         try { delete *i ; } catch(...) {}
00308       }
00309     }
00310   } catch(...){}
00311 }
00312 
00313 // Universal part constructor:
00314 Part::Part( MetaData * arg_meta_data )
00315   : m_name( universal_part_name() ),
00316     m_attribute(),
00317     m_subsets() , m_supersets() , m_intersect() , m_relations() ,
00318     m_mesh_meta_data( arg_meta_data ) ,
00319     m_universe_ordinal( 0 ),
00320     m_entity_rank( ~0u )
00321 {
00322   m_subsets.push_back( this );
00323 }
00324 
00325 // Subset part constructor:
00326 Part::Part( MetaData          * arg_meta_data ,
00327             const std::string & arg_name ,
00328             EntityType            arg_rank ,
00329             size_t              arg_ordinal )
00330   : m_name( arg_name ),
00331     m_attribute(),
00332     m_subsets() , m_supersets() , m_intersect() , m_relations() ,
00333     m_mesh_meta_data( arg_meta_data ),
00334     m_universe_ordinal( arg_ordinal ),
00335     m_entity_rank( arg_rank )
00336 {}
00337 
00338 //----------------------------------------------------------------------
00339 // A universal part may declare named subsets
00340 
00341 Part & Part::declare_part( const std::string & arg_name , EntityType arg_rank )
00342 {
00343   assert_universal_part( *this , "declare_part" );
00344 
00345   Part * p = find( m_subsets , arg_name );
00346 
00347   if ( p == NULL ) {
00348     p = new Part( m_mesh_meta_data , arg_name , arg_rank , m_subsets.size() );
00349     m_subsets.push_back( p );
00350     p->m_supersets.push_back( this );
00351   }
00352 
00353   if ( p->m_entity_rank != arg_rank ) {
00354     std::stringstream err;
00355     err << "Part of name '" << arg_name << "' of rank " << arg_rank << " already exists";
00356     throw std::runtime_error ( err.str() );
00357   }
00358 
00359   return *p ;
00360 }
00361 
00362 //----------------------------------------------------------------------
00363 // A universal part may declare intersection subsets
00364 
00365 Part & Part::declare_part( const PartVector & part_intersect )
00366 {
00367   static const char method[] = "declare_part" ;
00368 
00369   assert_universal_part( *this , method );
00370 
00371   PartVector pset_clean ;
00372 
00373   for ( PartVector::const_iterator
00374         i = part_intersect.begin() ; i != part_intersect.end() ; ++i ) {
00375     Part * const p = *i ;
00376     assert_contain( *this , *p , method );
00377 
00378     // If 'p' is a superset of another member
00379     // then it is redundant in this intersection.
00380     // Only keep non-redundant intersections.
00381 
00382     PartVector::const_iterator j = part_intersect.begin();
00383     for ( ; j != part_intersect.end() &&
00384             ! contain( (*j)->supersets() , *p ) ; ++j );
00385     if ( j == part_intersect.end() ) {
00386       pset_clean.push_back( p );
00387     }
00388   }
00389 
00390   // Sort and unique the intersection
00391   order( pset_clean );
00392 
00393   Part * p = NULL ;
00394   if ( 1 == pset_clean.size() ) {
00395     // Only one remaining part, it is the subset.
00396     p = pset_clean[0] ;
00397   }
00398   else {
00399     const char separator[] = "^" ;
00400 
00401     // Generate a name and rank reflecting the intersection.
00402     // Rank is the minimum rank of the intersection members.
00403 
00404     std::string p_name ;
00405     EntityType p_rank = std::numeric_limits<EntityType>::max();
00406 
00407     p_name.assign("{");
00408     for ( PartVector::iterator
00409           i = pset_clean.begin() ; i != pset_clean.end() ; ++i ) {
00410       if ( i != pset_clean.begin() ) { p_name.append( separator ); }
00411       p_name.append( (*i)->name() );
00412       if ( (*i)->primary_entity_type() < p_rank ) {
00413         p_rank = (*i)->primary_entity_type();
00414       }
00415     }
00416     p_name.append("}");
00417 
00418     p = find( m_subsets , p_name );
00419 
00420     if ( p == NULL ) {
00421 
00422       // Create the part:
00423 
00424       p = new Part( m_mesh_meta_data , p_name , p_rank , m_subsets.size() );
00425       m_subsets.push_back( p );
00426       p->m_supersets.push_back( this );
00427 
00428       // Define the part to be an intersection of the given parts:
00429 
00430       p->m_intersect = pset_clean ; // Copy
00431 
00432       for ( PartVector::iterator
00433             i = pset_clean.begin() ; i != pset_clean.end() ; ++i ) {
00434         (*i)->declare_subset( *p );
00435       }
00436     }
00437     else if ( pset_clean != p->m_intersect ) {
00438       // This error is "inconceivable" and is
00439       // only possible by heroic malicious abuse.
00440       std::string msg ;
00441       msg.append(method).append(p_name).append(" FAILED FROM MALICIOUS ABUSE");
00442       throw std::invalid_argument(msg);
00443     }
00444   }
00445 
00446   return *p ;
00447 }
00448 
00449 //----------------------------------------------------------------------
00450 
00451 void Part::declare_subset( Part & subset )
00452 {
00453   static const char method[] = "declare_subset" ;
00454 
00455   if ( ! contain( subset.supersets() , *this ) ) {
00456 
00457     assert_not_same( *this , method , subset );
00458     assert_not_superset(  *this , method , subset );
00459     assert_same_universe( *this , method , subset );
00460     assert_rank_ordering( *this , method , subset );
00461 
00462     // Insert this symmetric relationship first
00463     // so that it does not get revisited.
00464 
00465     insert( this->m_subsets , subset );
00466     insert( subset.m_supersets , *this );
00467 
00468     // Transitive:
00469 
00470     for ( PartVector::iterator
00471           i =  subset.m_subsets.begin() ; i != subset.m_subsets.end() ; ++i ) {
00472       declare_subset( **i );
00473     }
00474 
00475     for ( PartVector::iterator
00476           i =  m_supersets.begin() ; i != m_supersets.end() ; ++i ) {
00477       (*i)->declare_subset( subset );
00478     }
00479 
00480     // Induced intersection-part membership:
00481 
00482     for ( PartVector::iterator
00483           i =  m_subsets.begin() ;
00484           i != m_subsets.end() ; ++i ) {
00485 
00486       Part & pint = **i ;
00487 
00488       if ( ! pint.m_intersect.empty() && ( & pint != & subset ) ) {
00489 
00490         // If 'subset' is a subset of every member of 'pint.m_intersect'
00491         // then it is by definition a subset of 'pint.
00492         if ( contain( subset.m_supersets , pint.m_intersect ) ) {
00493           pint.declare_subset( subset );
00494         }
00495       }
00496     }
00497   }
00498 }
00499 
00500 //----------------------------------------------------------------------
00501 
00502 } // namespace mesh
00503 } // namespace stk
00504 

Generated on Tue Jul 13 09:27:32 2010 for Sierra Toolkit by  doxygen 1.4.7