Sierra Toolkit Version of the Day
TopologicalMetaData.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 <string>
00010 #include <vector>
00011 #include <sstream>
00012 #include <stdexcept>
00013 #include <algorithm>
00014 
00015 #include <Shards_BasicTopologies.hpp>
00016 
00017 #include <stk_mesh/base/MetaData.hpp>
00018 #include <stk_mesh/base/BulkData.hpp>
00019 #include <stk_mesh/base/Bucket.hpp>
00020 #include <stk_mesh/base/Entity.hpp>
00021 
00022 #include <stk_mesh/fem/TopologicalMetaData.hpp>
00023 
00024 namespace stk {
00025 namespace mesh {
00026 
00027 void TopologicalMetaData::verify_spatial_dimension(
00028   unsigned spatial_dimension , const char * method )
00029 {
00030   if ( spatial_dimension < 1 || 3 < spatial_dimension ) {
00031     std::ostringstream msg ;
00032     msg << method << " ERRONEOUS spatial dimension = "
00033         << spatial_dimension ;
00034     throw std::logic_error( msg.str() );
00035   }
00036 }
00037 
00038 std::vector<std::string>
00039 TopologicalMetaData::entity_rank_names( unsigned spatial_dimension )
00040 {
00041   static const char method[] =
00042     "stk::mesh::TopologicalMetaData::entity_rank_names" ;
00043 
00044   verify_spatial_dimension( spatial_dimension , method );
00045 
00046   std::vector< std::string > names ;
00047 
00048   names.reserve( spatial_dimension + 1 );
00049 
00050   names.push_back( std::string( "NODE" ) );
00051 
00052   if ( 1 < spatial_dimension ) { names.push_back( std::string("EDGE") ); }
00053   if ( 2 < spatial_dimension ) { names.push_back( std::string("FACE") ); }
00054 
00055   names.push_back( std::string("ELEMENT") );
00056   names.push_back( std::string("PATCH") );
00057 
00058   return names ;
00059 }
00060 
00061 const TopologicalMetaData *
00062 TopologicalMetaData::internal_get( const MetaData & meta_data )
00063 {
00064   return meta_data.get_attribute< TopologicalMetaData >();
00065 }
00066 
00067 TopologicalMetaData::~TopologicalMetaData()
00068 {
00069   m_meta_data.remove_attribute( this );
00070 }
00071 
00072 TopologicalMetaData::TopologicalMetaData(
00073   MetaData & arg_meta_data ,
00074   unsigned   arg_spatial_dimension )
00075   : spatial_dimension( arg_spatial_dimension )
00076   , node_rank( 0 )
00077   , edge_rank( 1 < spatial_dimension ? 1 : 0 )
00078   , side_rank( 2 < spatial_dimension ? 2 : edge_rank )
00079   , element_rank( spatial_dimension )
00080   , patch_rank( spatial_dimension + 1 )
00081   , m_meta_data( arg_meta_data )
00082   , m_top_rank()
00083   , m_part_top_map()
00084 {
00085   static const char method[] = "stk::mesh::TopologicalMetaData::TopologicalMetaData" ;
00086 
00087   verify_spatial_dimension( spatial_dimension , method );
00088 
00089   // Attach to the meta data
00090   m_meta_data.declare_attribute_no_delete< TopologicalMetaData >( this );
00091 
00092   // Load up appropriate standard cell topologies.
00093 
00094   declare_cell_topology( shards::getCellTopologyData< shards::Node >() , 0 );
00095 
00096   declare_cell_topology( shards::getCellTopologyData< shards::Line<2> >() , 1 );
00097   declare_cell_topology( shards::getCellTopologyData< shards::Line<3> >() , 1 );
00098 
00099   declare_cell_topology( shards::getCellTopologyData< shards::Particle >() , spatial_dimension );
00100 
00101   if ( 1 < spatial_dimension ) {
00102     declare_cell_topology( shards::getCellTopologyData< shards::Triangle<3> >() , 2 );
00103     declare_cell_topology( shards::getCellTopologyData< shards::Triangle<6> >() , 2 );
00104     declare_cell_topology( shards::getCellTopologyData< shards::Triangle<4> >() , 2 );
00105 
00106     declare_cell_topology( shards::getCellTopologyData< shards::Quadrilateral<4> >() , 2 );
00107     declare_cell_topology( shards::getCellTopologyData< shards::Quadrilateral<8> >() , 2 );
00108     declare_cell_topology( shards::getCellTopologyData< shards::Quadrilateral<9> >() , 2 );
00109 
00110     declare_cell_topology( shards::getCellTopologyData< shards::Beam<2> >() , spatial_dimension );
00111     declare_cell_topology( shards::getCellTopologyData< shards::Beam<3> >() , spatial_dimension );
00112   }
00113 
00114   if ( 2 == spatial_dimension ) {
00115     declare_cell_topology( shards::getCellTopologyData< shards::ShellLine<2> >() , 2 );
00116     declare_cell_topology( shards::getCellTopologyData< shards::ShellLine<3> >() , 2 );
00117   }
00118 
00119   if ( 2 < spatial_dimension ) {
00120     declare_cell_topology( shards::getCellTopologyData< shards::Tetrahedron<4> >() , 3 );
00121     declare_cell_topology( shards::getCellTopologyData< shards::Tetrahedron<10> >() , 3 );
00122     declare_cell_topology( shards::getCellTopologyData< shards::Tetrahedron<8> >() , 3 );
00123 
00124     declare_cell_topology( shards::getCellTopologyData< shards::Pyramid<5> >() , 3 );
00125     declare_cell_topology( shards::getCellTopologyData< shards::Pyramid<13> >() , 3 );
00126     declare_cell_topology( shards::getCellTopologyData< shards::Pyramid<14> >() , 3 );
00127 
00128     declare_cell_topology( shards::getCellTopologyData< shards::Wedge<6> >() , 3 );
00129     declare_cell_topology( shards::getCellTopologyData< shards::Wedge<15> >() , 3 );
00130     declare_cell_topology( shards::getCellTopologyData< shards::Wedge<18> >() , 3 );
00131 
00132     declare_cell_topology( shards::getCellTopologyData< shards::Hexahedron<8> >() , 3 );
00133     declare_cell_topology( shards::getCellTopologyData< shards::Hexahedron<20> >() , 3 );
00134     declare_cell_topology( shards::getCellTopologyData< shards::Hexahedron<27> >() , 3 );
00135 
00136     declare_cell_topology( shards::getCellTopologyData< shards::ShellTriangle<3> >() , 3 );
00137     declare_cell_topology( shards::getCellTopologyData< shards::ShellTriangle<6> >() , 3 );
00138 
00139     declare_cell_topology( shards::getCellTopologyData< shards::ShellQuadrilateral<4> >() , 3 );
00140     declare_cell_topology( shards::getCellTopologyData< shards::ShellQuadrilateral<8> >() , 3 );
00141     declare_cell_topology( shards::getCellTopologyData< shards::ShellQuadrilateral<9> >() , 3 );
00142   }
00143 }
00144 
00145 //----------------------------------------------------------------------------
00146 
00147 EntityRank TopologicalMetaData::get_entity_rank( const CellTopologyData * top ) const
00148 {
00149   typedef std::pair< const CellTopologyData * , EntityRank > ValueType ;
00150 
00151   std::vector< ValueType >::const_iterator i ;
00152 
00153   for ( i = m_top_rank.begin() ; i != m_top_rank.end() && top != i->first ; ++i );
00154 
00155   if (i == m_top_rank.end()) {
00156     throw std::runtime_error("stk::mesh::TopologicalMetaData::get_entity_rank ERROR, topology not found.");
00157   }
00158 
00159   return i->second ;
00160 }
00161 
00162 void TopologicalMetaData::internal_set_entity_rank( const CellTopologyData * top , EntityRank rank )
00163 {
00164   typedef std::pair< const CellTopologyData * , EntityRank > ValueType ;
00165 
00166   m_top_rank.push_back( ValueType( top , rank ) );
00167 }
00168 
00169 //----------------------------------------------------------------------------
00170 
00171 void TopologicalMetaData::declare_cell_topology(
00172   const CellTopologyData * top , EntityRank rank )
00173 {
00174   static const char method[] = "stk::mesh::TopologicalMetaData::declare_cell_topology" ;
00175 
00176   typedef std::pair< const CellTopologyData * , EntityRank > ValueType ;
00177 
00178   std::vector< ValueType >::const_iterator i = m_top_rank.begin() ;
00179   for ( ; i != m_top_rank.end() && top != i->first ; ++i );
00180 
00181   const bool       duplicate     = i != m_top_rank.end();
00182   const EntityRank existing_rank = duplicate ? i->second : 0 ;
00183 
00184   const bool error_change = duplicate && existing_rank != rank ;
00185   const bool error_rank   = spatial_dimension < rank ;
00186 
00187   if ( error_rank || error_change ) {
00188     std::ostringstream msg ;
00189     msg << method << "( " << top->name
00190         << " , rank = " << rank << " ) ERROR " ;
00191     if ( error_rank ) {
00192       msg << ": rank exceeds maximum spatial_dimension = "
00193           << spatial_dimension ;
00194     }
00195     if ( error_change ) {
00196       msg << ": previously declared rank = " << existing_rank ;
00197     }
00198     throw std::runtime_error( msg.str() );
00199   }
00200 
00201   if ( ! duplicate ) {
00202     internal_set_entity_rank( top , rank );
00203   }
00204 }
00205 
00206 //----------------------------------------------------------------------------
00207 
00208 Part & TopologicalMetaData::declare_part(
00209   const std::string & name , const CellTopologyData * top )
00210 {
00211   //static const char method[] = "stk::mesh::TopologicalMetaData::declare_part" ;
00212 
00213   EntityRank entity_rank;
00214   try {
00215     entity_rank = get_entity_rank( top );
00216   }
00217   catch(std::runtime_error& /*x*/) {
00218     internal_set_entity_rank( top , top->dimension );
00219     entity_rank = top->dimension ;
00220   }
00221 
00222   Part & part = m_meta_data.declare_part( name , entity_rank );
00223 
00224   internal_set_cell_topology(part, entity_rank, top);
00225   return part ;
00226 }
00227 
00228 //----------------------------------------------------------------------------
00229 
00230 void TopologicalMetaData::internal_set_cell_topology( 
00231     Part & part, 
00232     unsigned entity_rank, 
00233     const CellTopologyData * top
00234     ) 
00235 {
00236   static const char method[] = "stk::mesh::TopologicalMetaData::internal_set_cell_topology" ;
00237   typedef std::pair< PartOrdinal , const CellTopologyData * > ValueType ;
00238   ValueType value( part.mesh_meta_data_ordinal() , top );
00239 
00240   std::vector< ValueType >::iterator
00241     i = std::lower_bound( m_part_top_map.begin() , m_part_top_map.end() , value );
00242 
00243   const bool duplicate  = i != m_part_top_map.end() && i->first == value.first ;
00244   const bool error_rank = part.primary_entity_rank() != entity_rank ;
00245   const bool error_top  = duplicate && i->second != value.second ;
00246 
00247   if ( error_rank || error_top ) {
00248     std::ostringstream msg ;
00249     msg << method << "( " << part.name()
00250         << " , " << top->name << " ) ERROR " ;
00251     if ( error_rank ) {
00252       msg << ": different entity_rank " << part.primary_entity_rank()
00253           << " != " << entity_rank ;
00254     }
00255     if ( error_top ) {
00256       msg << ": different topology " << i->second->name
00257           << " != " << top->name ;
00258     }
00259     throw msg.str();
00260   }
00261 
00262   if ( ! duplicate ) {
00263     m_part_top_map.insert( i , value );
00264   }
00265 
00266 }
00267 
00268 //----------------------------------------------------------------------------
00269 
00270 const CellTopologyData *
00271 TopologicalMetaData::internal_get_cell_topology( PartOrdinal part_ordinal ) const
00272 {
00273   typedef std::pair< PartOrdinal , const CellTopologyData * > ValueType ;
00274 
00275   ValueType tmp( part_ordinal , NULL );
00276 
00277   std::vector< ValueType >::const_iterator
00278     i = std::lower_bound( m_part_top_map.begin() , m_part_top_map.end() , tmp );
00279 
00280   return i != m_part_top_map.end() && i->first == part_ordinal ? i->second : NULL ;
00281 }
00282 
00283 //----------------------------------------------------------------------------
00284 
00285 void TopologicalMetaData::throw_ambiguous( const Part & part ) const
00286 {
00287   static const char method[] = "stk::mesh::get_cell_topology" ;
00288 
00289   const PartVector & supersets = part.supersets();
00290 
00291   std::ostringstream msg ;
00292 
00293   msg << method << "( Part[" << part.name()
00294       << "] ) has ambiguous cell topology {" ;
00295 
00296   for ( PartVector::const_iterator
00297         j = supersets.begin(); j != supersets.end() ; ++j ) {
00298 
00299     const CellTopologyData * const top =
00300       internal_get_cell_topology( (*j)->mesh_meta_data_ordinal() );
00301 
00302     if ( top ) {
00303       msg << " ( Superset[" << (*j)->name()
00304           << "] -> " << top->name << " )" ;
00305     }
00306   }
00307 
00308   msg << " }" ;
00309   throw std::runtime_error( msg.str() );
00310 }
00311 
00312 void TopologicalMetaData::throw_ambiguous( const Bucket & bucket ) const
00313 {
00314   static const char method[] = "stk::mesh::get_cell_topology" ;
00315 
00316   const PartVector & all_parts = m_meta_data.get_parts();
00317 
00318   std::ostringstream msg ;
00319 
00320   msg << method << "( Bucket ) has ambiguous cell topology {" ;
00321 
00322   const std::pair< const unsigned * , const unsigned * >
00323     supersets = bucket.superset_part_ordinals();
00324 
00325   for ( const unsigned * j = supersets.first ; j != supersets.second ; ++j ) {
00326     const CellTopologyData * const top =
00327       internal_get_cell_topology( *j );
00328     if ( top ) {
00329       msg << " ( Superset[" << all_parts[*j]->name()
00330           << "] -> " << top->name << " )" ;
00331     }
00332   }
00333   msg << " }" ;
00334   throw std::runtime_error( msg.str() );
00335 }
00336 
00337 void TopologicalMetaData::throw_required( const Part & part ,
00338                                           const char * required_by )
00339 {
00340   static const char method[] = "stk::mesh::get_cell_topology" ;
00341 
00342   std::ostringstream msg ;
00343 
00344   msg << required_by << " Failed to obtain cell topology from "
00345       << method << "( Part[" << part.name() << "] );" ;
00346 
00347   throw std::runtime_error( msg.str() );
00348 }
00349 
00350 void TopologicalMetaData::throw_required( const Bucket & bucket ,
00351                                           const char * required_by )
00352 {
00353   static const char method[] = "stk::mesh::get_cell_topology" ;
00354 
00355   std::ostringstream msg ;
00356 
00357   msg << required_by << " Failed to obtain cell topology from "
00358       << method << "( Bucket[" ;
00359 
00360   const BulkData   & bulk_data = bucket.mesh();
00361   const MetaData   & meta_data = bulk_data.mesh_meta_data();
00362   const PartVector & all_parts = meta_data.get_parts();
00363 
00364   const std::pair< const unsigned * , const unsigned * >
00365     supersets = bucket.superset_part_ordinals();
00366 
00367   for ( const unsigned * j = supersets.first ; j != supersets.second ; ++j ) {
00368     msg << " " << all_parts[*j]->name();
00369   }
00370 
00371   msg << " ] )" ;
00372 
00373   throw std::runtime_error( msg.str() );
00374 }
00375 
00376 //----------------------------------------------------------------------------
00377 
00378 const CellTopologyData *
00379 TopologicalMetaData::get_cell_topology( const Part & part ,
00380                                         const char * required_by )
00381 {
00382   const TopologicalMetaData * const self = internal_get( part.mesh_meta_data() );
00383 
00384   const CellTopologyData * cell_top = NULL ;
00385 
00386   if ( self ) {
00387     cell_top = self->internal_get_cell_topology( part.mesh_meta_data_ordinal() );
00388 
00389     if ( ! cell_top ) {
00390       const PartVector & supersets = part.supersets();
00391 
00392       for ( PartVector::const_iterator
00393             j = supersets.begin(); j != supersets.end() ; ++j ) {
00394 
00395         const CellTopologyData * const top =
00396           self->internal_get_cell_topology( (*j)->mesh_meta_data_ordinal() );
00397 
00398         if ( ! cell_top ) {
00399           cell_top = top ;
00400         }
00401         else if ( top && top != cell_top ) {
00402           self->throw_ambiguous( part );
00403         }
00404       }
00405     }
00406   }
00407 
00408   if ( ! cell_top && required_by ) {
00409     throw_required( part , required_by );
00410   }
00411 
00412   return cell_top ;
00413 }
00414 
00415 //----------------------------------------------------------------------------
00416 
00417 const CellTopologyData *
00418 TopologicalMetaData::get_cell_topology( const Bucket & bucket ,
00419                                         const char * required_by )
00420 {
00421   const BulkData   & bulk_data = bucket.mesh();
00422   const MetaData   & meta_data = bulk_data.mesh_meta_data();
00423   const PartVector & all_parts = meta_data.get_parts();
00424 
00425   const TopologicalMetaData * const self = internal_get( meta_data );
00426 
00427   const CellTopologyData * cell_top = NULL ;
00428 
00429   if ( self ) {
00430     const std::pair< const unsigned * , const unsigned * >
00431       supersets = bucket.superset_part_ordinals();
00432 
00433     for ( const unsigned * j = supersets.first ; j != supersets.second ; ++j ) {
00434 
00435       const Part & part = * all_parts[*j] ;
00436 
00437       if ( part.primary_entity_rank() == bucket.entity_rank() ) {
00438 
00439         const CellTopologyData * const top =
00440           self->internal_get_cell_topology( *j );
00441 
00442         if ( ! cell_top ) {
00443           cell_top = top ;
00444         }
00445         else if ( top && top != cell_top ) {
00446           self->throw_ambiguous( bucket );
00447         }
00448       }
00449     }
00450   }
00451 
00452   if ( ! cell_top && required_by ) {
00453     throw_required( bucket , required_by );
00454   }
00455 
00456   return cell_top ;
00457 }
00458 
00459 //----------------------------------------------------------------------------
00460 
00461 const CellTopologyData *
00462 TopologicalMetaData::get_cell_topology( const Entity & entity ,
00463                                         const char * required_by )
00464 {
00465   return get_cell_topology( entity.bucket(), required_by );
00466 }
00467 
00468 }
00469 }
00470 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends