Sierra Toolkit Version of the Day
UnitTestRelation.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 <sstream>
00011 #include <stdexcept>
00012 #include <iostream>
00013 
00014 /*#include <cppunit/TestCase.h>
00015 #include <cppunit/extensions/HelperMacros.h>
00016 #include <cppunit/extensions/TestFactoryRegistry.h>
00017 #include <cppunit/ui/text/TestRunner.h>
00018 */
00019 #include <stk_util/unit_test_support/stk_utest_macros.hpp>
00020 
00021 #include <stk_util/parallel/Parallel.hpp>
00022 #include <stk_mesh/base/BulkData.hpp>
00023 #include <stk_mesh/base/GetEntities.hpp>
00024 #include <stk_mesh/base/Field.hpp>
00025 #include <stk_mesh/base/FieldData.hpp>
00026 #include <stk_mesh/base/Comm.hpp>
00027 #include <stk_mesh/base/EntityComm.hpp>
00028 #include <stk_mesh/fem/EntityRanks.hpp>
00029 
00030 #include <unit_tests/UnitTestRelation.hpp>
00031 #include <unit_tests/UnitTestBulkData.hpp>
00032 #include <unit_tests/UnitTestRingMeshFixture.hpp>
00033 
00034 #include <Shards_BasicTopologies.hpp>
00035 #include <stk_mesh/fem/TopologyHelpers.hpp>
00036 #include <stk_mesh/fem/TopologicalMetaData.hpp>
00037 
00038 /*class UnitTestingOfRelation : public ::CppUnit::TestCase {
00039 private:
00040   CPPUNIT_TEST_SUITE( UnitTestingOfRelation );
00041   CPPUNIT_TEST( testUnit );
00042   CPPUNIT_TEST_SUITE_END();
00043 
00044 public:
00045   UnitTestingOfRelation() : CppUnit::TestCase() {}
00046 
00047   void setUp() {}
00048   void tearDown() {}
00049   void testUnit();
00050 };
00051 
00052 CPPUNIT_TEST_SUITE_REGISTRATION( UnitTestingOfRelation );
00053 
00054 void UnitTestingOfRelation::testUnit()
00055 {
00056   MPI_Barrier( MPI_COMM_WORLD );
00057   stk::mesh::UnitTestRelation::testRelation ( MPI_COMM_WORLD );
00058 }
00059 */
00060 
00061 STKUNIT_UNIT_TEST(UnitTestingOfRelation, testUnit)
00062 {
00063   MPI_Barrier ( MPI_COMM_WORLD );
00064   stk::mesh::UnitTestRelation::testRelation ( MPI_COMM_WORLD );
00065 }
00066 
00067 //----------------------------------------------------------------------
00068 //----------------------------------------------------------------------
00069 
00070 namespace stk {
00071 namespace mesh {
00072 
00073 
00074 // Unit test the Part functionality in isolation:
00075 
00076 void UnitTestRelation::testRelation( ParallelMachine pm )
00077 {
00078   typedef Field<double>  ScalarFieldType;
00079  // static const char method[] = "stk::mesh::UnitTestRelation" ;
00080 
00081  // Create a mesh for testing buckets
00082   std::cout << std::endl ;
00083 
00084   std::vector<std::string> entity_names(10);
00085   for ( size_t i = 0 ; i < 10 ; ++i ) {
00086     std::ostringstream name ;
00087     name << "EntityRank" << i ;
00088     entity_names[i] = name.str();
00089   }
00090 
00091   MetaData meta( entity_names );
00092   MetaData meta2 ( entity_names );
00093   const int spatial_dimension = 3;
00094   TopologicalMetaData top( meta, spatial_dimension );
00095   TopologicalMetaData top2( meta2, spatial_dimension );
00096 
00097   BulkData bulk( meta , pm , 4 );
00098   BulkData bulk2( meta2 , pm , 4 );
00099 
00100   ScalarFieldType & temperature =
00101        meta.declare_field < ScalarFieldType > ( "temperature" , 4 );
00102   ScalarFieldType & volume =
00103        meta.declare_field < ScalarFieldType > ( "volume" , 4 );
00104   ScalarFieldType & temperature2 =
00105        meta2.declare_field < ScalarFieldType > ( "temperature" , 4 );
00106   ScalarFieldType & volume2 =
00107        meta2.declare_field < ScalarFieldType > ( "volume" , 4 );
00108 
00109   Part  & universal     = meta.universal_part ();
00110   Part  & universal2    = meta2.universal_part ();
00111   Part  & owned         = meta.locally_owned_part ();
00112 
00113   put_field ( temperature , top.node_rank , universal );
00114   put_field ( volume , top.element_rank , universal );
00115   meta.commit();
00116   put_field ( temperature2 , top2.node_rank , universal2 );
00117   put_field ( volume2 , top2.element_rank , universal2 );
00118   meta2.commit();
00119 
00120 
00121   bulk.modification_begin();
00122   bulk2.modification_begin();
00123 
00124   const int root_box[3][2] = { { 0,4 } , { 0,5 } , { 0,6 } };
00125   int local_box[3][2] = { { 0,0 } , { 0,0 } , { 0,0 } };
00126   generate_boxes( bulk , false /* no aura */ , root_box , local_box );
00127   generate_boxes( bulk2 , false /* no aura */ , root_box , local_box );
00128 
00129 
00130   Entity &cell = *(bulk.buckets (3)[0]->begin());
00131   Entity &node = bulk.buckets (0)[0]-> operator [] ( 0 );
00132   Entity &nodeb = bulk.buckets (0)[0]-> operator [] ( 2 );
00133 
00134   std::vector<Part *> parts;
00135   parts.push_back ( &universal );
00136   parts.push_back ( &owned );
00137   bulk.modification_begin();
00138   stk::mesh::EntityId  new_id = bulk.parallel_rank() + 1;
00139   Entity &edge = bulk.declare_entity ( 1 , new_id , parts );
00140 
00141   Entity &cell2 = *(bulk2.buckets (3)[0]->begin());
00142   Entity &node2 = *(bulk2.buckets (0)[0]->begin());
00143 
00144 
00145   STKUNIT_ASSERT_THROW ( Relation r ( Relation::attribute( 2 , 0 ) , cell ) , std::invalid_argument );
00146 
00147   {
00148       int ok = 0 ;
00149     try {
00150 
00151   unsigned id = 10000*(~(0u));
00152 
00153   Relation r (Relation::attribute( 0 , id ), cell );
00154 
00155     }
00156     catch( const std::exception & x ) {
00157       ok = 1 ;
00158       std::cout << "UnitRelation CORRECTLY caught error for : "
00159                 << x.what()
00160                 << std::endl ;
00161     }
00162 
00163     if ( ! ok ) {
00164       throw std::runtime_error("UnitTestRelation FAILED to catch error for Relation::attribute");
00165     }
00166   } 
00167 
00168   STKUNIT_ASSERT_THROW ( bulk.declare_relation ( node , cell , 0 ) , std::runtime_error );
00169   STKUNIT_ASSERT_THROW ( bulk.declare_relation ( cell , node2 , 0 ) , std::runtime_error );
00170   STKUNIT_ASSERT_THROW ( bulk.declare_relation ( cell2 , node , 0 ) , std::runtime_error );
00171 
00172 
00173   bulk.declare_relation ( edge , node , 1 );
00174   STKUNIT_ASSERT_THROW ( bulk.declare_relation ( edge , nodeb , 1 ) , std::runtime_error );
00175   bulk.declare_relation ( edge , nodeb , 2 );
00176 
00177   std::stringstream s;
00178   s << *edge.relations().first ;
00179 
00180   bulk.modification_end();
00181 
00182   //Testing on in_send_ghost and in_shared in EntityComm.cpp
00183   enum { nPerProc = 10 };
00184   const unsigned p_rank = parallel_machine_rank( pm );
00185   const unsigned p_size = parallel_machine_size( pm );
00186 
00187 
00188   const unsigned nLocalEdge = nPerProc ;
00189   MetaData meta3( TopologicalMetaData::entity_rank_names(spatial_dimension) );
00190 
00191   meta3.commit();
00192 
00193   Selector select_owned( meta3.locally_owned_part() );
00194   Selector select_used = meta3.locally_owned_part() ; 
00195   Selector select_all(  meta3.universal_part() );
00196  
00197   PartVector no_parts ;
00198    
00199   std::vector<unsigned> local_count ;
00200 
00201   //------------------------------
00202   { // No ghosting
00203 
00204     const bool aura_flag = false ;
00205     UnitTestRingMeshFixture mesh2( pm , nPerProc , false /* No edge parts */ );
00206     mesh2.m_meta_data.commit();
00207     mesh2.generate_mesh( aura_flag );
00208 
00209     // This process' first element in the loop
00210     // if a parallel mesh has a shared node
00211 
00212     Entity * edgenew = mesh2.m_bulk_data.get_entity( 1 , mesh2.m_edge_ids[ nLocalEdge * p_rank ] );
00213 
00214     mesh2.m_bulk_data.modification_begin();
00215     for ( unsigned p = 0 ; p < p_size ; ++p ) if ( p != p_rank ) {
00216       STKUNIT_ASSERT_EQUAL( in_shared( *edgenew , p ), false );
00217       STKUNIT_ASSERT_EQUAL( in_send_ghost( *edgenew , p ), false );
00218     }
00219 
00220       Entity * edgenew2 = mesh2.m_bulk_data.get_entity( 1 , mesh2.m_edge_ids[ nLocalEdge * p_rank ] );
00221       STKUNIT_ASSERT_EQUAL( in_send_ghost( *edgenew2 , p_rank+100 ), false );
00222 
00223       Entity * node3 = mesh2.m_bulk_data.get_entity( 0 , mesh2.m_node_ids[ nLocalEdge * p_rank ] );
00224       STKUNIT_ASSERT_EQUAL( in_shared( *node3 , p_rank+100 ), false );     
00225  
00226   }
00227 
00228 
00229   {//ghosting
00230 
00231   if ( 1 < p_size ) { // With ghosting
00232     const bool aura_flag = true ;
00233 
00234     UnitTestRingMeshFixture mesh3( pm , nPerProc , false /* No edge parts */ );
00235     mesh3.m_meta_data.commit();
00236     mesh3.generate_mesh( aura_flag );
00237     const unsigned nNotOwned = nPerProc * p_rank ;
00238 
00239     // The not-owned shared entity:
00240     Entity * node3 = mesh3.m_bulk_data.get_entity( 0 , mesh3.m_node_ids[ nNotOwned ] );
00241     Entity * node4 = mesh3.m_bulk_data.get_entity( 0 , mesh3.m_node_ids[ nNotOwned ] );
00242 
00243 
00244     EntityId node_edge_ids[2] ;
00245     node_edge_ids[0] = node3->relations()[0].entity()->identifier();
00246     node_edge_ids[1] = node3->relations()[1].entity()->identifier();
00247 
00248     mesh3.m_bulk_data.modification_begin();
00249 
00250     for ( unsigned p = 0 ; p < p_size ; ++p ) if ( p != p_rank ) {
00251       //FIXME for Carol the check below did not pass for -np 3 or 4
00252       //STKUNIT_ASSERT_EQUAL( in_shared( *node3 , p ), true );
00253       STKUNIT_ASSERT_EQUAL( in_send_ghost( *node3 , p ), false );
00254     }
00255 
00256     //not owned and not shared
00257     Entity * node5 = mesh3.m_bulk_data.get_entity( 0 , mesh3.m_node_ids[ nLocalEdge * p_rank ] );
00258 
00259     node_edge_ids[0] = node5->relations()[0].entity()->identifier();
00260     node_edge_ids[1] = node5->relations()[1].entity()->identifier();
00261 
00262     STKUNIT_ASSERT_EQUAL( in_shared( *node5 , p_rank+100 ), false );
00263     STKUNIT_ASSERT_EQUAL( in_send_ghost( *node4 , p_rank+100 ), false );
00264   }
00265 
00266 } 
00267 
00268 }
00269 
00270 //----------------------------------------------------------------------
00271 
00272 namespace {
00273 
00274 /* Recursively split a box into ( up - ip ) sub-boxes */
00275 
00276 typedef int BOX[3][2] ;
00277 
00278 void box_partition( int ip , int up , int axis ,
00279                     const BOX box ,
00280                     BOX p_box[] )
00281 {
00282   const int np = up - ip ;
00283   if ( 1 == np ) {
00284     p_box[ip][0][0] = box[0][0] ; p_box[ip][0][1] = box[0][1] ;
00285     p_box[ip][1][0] = box[1][0] ; p_box[ip][1][1] = box[1][1] ;
00286     p_box[ip][2][0] = box[2][0] ; p_box[ip][2][1] = box[2][1] ;
00287   }
00288   else {
00289     const int n = box[ axis ][1] - box[ axis ][0] ;
00290     const int np_low = np / 2 ;  /* Rounded down */
00291     const int np_upp = np - np_low ;
00292 
00293     const int n_upp = (int) (((double) n) * ( ((double)np_upp) / ((double)np)));
00294     const int n_low = n - n_upp ;
00295     const int next_axis = ( axis + 2 ) % 3 ;
00296 
00297     if ( np_low ) { /* P = [ip,ip+np_low) */
00298       BOX dbox ;
00299       dbox[0][0] = box[0][0] ; dbox[0][1] = box[0][1] ;
00300       dbox[1][0] = box[1][0] ; dbox[1][1] = box[1][1] ;
00301       dbox[2][0] = box[2][0] ; dbox[2][1] = box[2][1] ;
00302 
00303       dbox[ axis ][1] = dbox[ axis ][0] + n_low ;
00304 
00305       box_partition( ip, ip + np_low, next_axis,
00306                      (const int (*)[2]) dbox, p_box );
00307     }
00308 
00309     if ( np_upp ) { /* P = [ip+np_low,ip+np_low+np_upp) */
00310       BOX dbox ;
00311       dbox[0][0] = box[0][0] ; dbox[0][1] = box[0][1] ;
00312       dbox[1][0] = box[1][0] ; dbox[1][1] = box[1][1] ;
00313       dbox[2][0] = box[2][0] ; dbox[2][1] = box[2][1] ;
00314 
00315       ip += np_low ;
00316       dbox[ axis ][0] += n_low ;
00317       dbox[ axis ][1]  = dbox[ axis ][0] + n_upp ;
00318 
00319       box_partition( ip, ip + np_upp, next_axis,
00320                      (const int (*)[2]) dbox, p_box );
00321     }
00322   }
00323 }
00324 
00325 }
00326 
00327 void UnitTestRelation::generate_boxes(
00328   BulkData  & mesh ,
00329   const bool  generate_aura ,
00330   const int   root_box[][2] ,
00331         int   local_box[][2] )
00332 {
00333   const unsigned p_rank = mesh.parallel_rank();
00334   const unsigned p_size = mesh.parallel_size();
00335   const unsigned ngx = root_box[0][1] - root_box[0][0] ;
00336   const unsigned ngy = root_box[1][1] - root_box[1][0] ;
00337   const unsigned ngz = root_box[2][1] - root_box[2][0] ;
00338 /*
00339   const unsigned e_global = ngx * ngy * ngz ;
00340   const unsigned n_global = ( ngx + 1 ) * ( ngy + 1 ) * ( ngz + 1 );
00341 */
00342 
00343   if ( 0 == p_rank ) {
00344     std::cout << "Global box = " << ngx << " x " << ngy << " x " << ngz
00345               << std::endl ;
00346   }
00347 
00348   BOX * const p_box = new BOX[ p_size ];
00349 
00350   box_partition( 0 , p_size , 2 , root_box , & p_box[0] );
00351 
00352   local_box[0][0] = p_box[ p_rank ][0][0] ;
00353   local_box[0][1] = p_box[ p_rank ][0][1] ;
00354   local_box[1][0] = p_box[ p_rank ][1][0] ;
00355   local_box[1][1] = p_box[ p_rank ][1][1] ;
00356   local_box[2][0] = p_box[ p_rank ][2][0] ;
00357   local_box[2][1] = p_box[ p_rank ][2][1] ;
00358 
00359   const unsigned nx = local_box[0][1] - local_box[0][0] ;
00360   const unsigned ny = local_box[1][1] - local_box[1][0] ;
00361   const unsigned nz = local_box[2][1] - local_box[2][0] ;
00362 
00363   const unsigned e_local = nx * ny * nz ;
00364   const unsigned n_local = ( nx + 1 ) * ( ny + 1 ) * ( nz + 1 );
00365 
00366   // Create elements:
00367 
00368   std::vector<unsigned> local_count ;
00369 
00370   const PartVector no_parts ;
00371 
00372   for ( int k = local_box[2][0] ; k < local_box[2][1] ; ++k ) {
00373   for ( int j = local_box[1][0] ; j < local_box[1][1] ; ++j ) {
00374   for ( int i = local_box[0][0] ; i < local_box[0][1] ; ++i ) {
00375     const EntityId n0 = 1 + (i+0) + (j+0) * (ngx+1) + (k+0) * (ngx+1) * (ngy+1);
00376     const EntityId n1 = 1 + (i+1) + (j+0) * (ngx+1) + (k+0) * (ngx+1) * (ngy+1);
00377     const EntityId n2 = 1 + (i+1) + (j+1) * (ngx+1) + (k+0) * (ngx+1) * (ngy+1);
00378     const EntityId n3 = 1 + (i+0) + (j+1) * (ngx+1) + (k+0) * (ngx+1) * (ngy+1);
00379     const EntityId n4 = 1 + (i+0) + (j+0) * (ngx+1) + (k+1) * (ngx+1) * (ngy+1);
00380     const EntityId n5 = 1 + (i+1) + (j+0) * (ngx+1) + (k+1) * (ngx+1) * (ngy+1);
00381     const EntityId n6 = 1 + (i+1) + (j+1) * (ngx+1) + (k+1) * (ngx+1) * (ngy+1);
00382     const EntityId n7 = 1 + (i+0) + (j+1) * (ngx+1) + (k+1) * (ngx+1) * (ngy+1);
00383 
00384     const EntityId elem_id =  1 + i + j * ngx + k * ngx * ngy;
00385 
00386     Entity & node0 = mesh.declare_entity( 0 , n0 , no_parts );
00387     Entity & node1 = mesh.declare_entity( 0 , n1 , no_parts );
00388     Entity & node2 = mesh.declare_entity( 0 , n2 , no_parts );
00389     Entity & node3 = mesh.declare_entity( 0 , n3 , no_parts );
00390     Entity & node4 = mesh.declare_entity( 0 , n4 , no_parts );
00391     Entity & node5 = mesh.declare_entity( 0 , n5 , no_parts );
00392     Entity & node6 = mesh.declare_entity( 0 , n6 , no_parts );
00393     Entity & node7 = mesh.declare_entity( 0 , n7 , no_parts );
00394     Entity & elem  = mesh.declare_entity( 3 , elem_id , no_parts );
00395 
00396     mesh.declare_relation( elem , node0 , 0 );
00397     mesh.declare_relation( elem , node1 , 1 );
00398     mesh.declare_relation( elem , node2 , 2 );
00399     mesh.declare_relation( elem , node3 , 3 );
00400     mesh.declare_relation( elem , node4 , 4 );
00401     mesh.declare_relation( elem , node5 , 5 );
00402     mesh.declare_relation( elem , node6 , 6 );
00403     mesh.declare_relation( elem , node7 , 7 );
00404 
00405     std::vector<Entity*> nodes(8);
00406     std::vector<Entity*> elems ;
00407     nodes[0] = & node0 ;
00408     nodes[1] = & node1 ;
00409     nodes[2] = & node2 ;
00410     nodes[3] = & node3 ;
00411     nodes[4] = & node4 ;
00412     nodes[5] = & node5 ;
00413     nodes[6] = & node6 ;
00414     nodes[7] = & node7 ;
00415 
00416     get_entities_through_relations( nodes , elems );
00417     STKUNIT_ASSERT_EQUAL( elems.size() , size_t(1) );
00418     STKUNIT_ASSERT_EQUAL( elems[0] , & elem );
00419 
00420     get_entities_through_relations( nodes , 3 , elems );
00421     STKUNIT_ASSERT_EQUAL( elems.size() , size_t(1) );
00422     STKUNIT_ASSERT_EQUAL( elems[0] , & elem );
00423 
00424   }
00425   }
00426   }
00427 
00428   Selector select_owned( mesh.mesh_meta_data().locally_owned_part() );
00429 
00430   Selector select_used = mesh.mesh_meta_data().locally_owned_part() |
00431                          mesh.mesh_meta_data().globally_shared_part();
00432 
00433   Selector select_all(mesh.mesh_meta_data().universal_part());
00434 
00435   count_entities( select_used , mesh , local_count );
00436   STKUNIT_ASSERT_EQUAL( e_local , local_count[3] );
00437   STKUNIT_ASSERT_EQUAL( 0u , local_count[2] );
00438   STKUNIT_ASSERT_EQUAL( 0u , local_count[1] );
00439   STKUNIT_ASSERT_EQUAL( n_local , local_count[0] );
00440 
00441   //Set up ghosting
00442   const Ghosting & gg = mesh.create_ghosting( std::string("shared") );
00443 
00444   // Set up sharing:
00445   mesh.modification_end();
00446 
00447 
00448   // Verify declarations and sharing
00449 
00450   count_entities( select_used , mesh , local_count );
00451   STKUNIT_ASSERT( local_count[3] == e_local );
00452   STKUNIT_ASSERT( local_count[2] == 0 );
00453   STKUNIT_ASSERT( local_count[1] == 0 );
00454   STKUNIT_ASSERT( local_count[0] == n_local );
00455 
00456   for ( int k = local_box[2][0] ; k <= local_box[2][1] ; ++k ) {
00457   for ( int j = local_box[1][0] ; j <= local_box[1][1] ; ++j ) {
00458   for ( int i = local_box[0][0] ; i <= local_box[0][1] ; ++i ) {
00459     EntityRank node_type = 0;
00460     EntityId node_id = 1 + i + j * (ngx+1) + k * (ngx+1) * (ngy+1);
00461     Entity * const node = mesh.get_entity( node_type , node_id );
00462     STKUNIT_ASSERT( node != NULL );
00463     // Shared if on a processor boundary.
00464     const bool shared =
00465       ( k == local_box[2][0] && k != root_box[2][0] ) ||
00466       ( k == local_box[2][1] && k != root_box[2][1] ) ||
00467       ( j == local_box[1][0] && j != root_box[1][0] ) ||
00468       ( j == local_box[1][1] && j != root_box[1][1] ) ||
00469       ( i == local_box[0][0] && i != root_box[0][0] ) ||
00470       ( i == local_box[0][1] && i != root_box[0][1] );
00471     STKUNIT_ASSERT_EQUAL( shared , ! node->sharing().empty() );
00472   }
00473   }
00474   }
00475 
00476 
00477   for ( unsigned p = 0 ; p < p_size ; ++p ) if ( p != p_rank ) {
00478     for ( int k = p_box[p][2][0] ; k <= p_box[p][2][1] ; ++k )
00479     if ( local_box[2][0] <= k && k <= local_box[2][1] ) {
00480 
00481       for ( int j = p_box[p][1][0] ; j <= p_box[p][1][1] ; ++j )
00482       if ( local_box[1][0] <= j && j <= local_box[1][1] ) {
00483 
00484         for ( int i = p_box[p][0][0] ; i <= p_box[p][0][1] ; ++i )
00485         if ( local_box[0][0] <= i && i <= local_box[0][1] ) {
00486 
00487           EntityRank node_type = 0;
00488           EntityId node_id = 1 + i + j * (ngx+1) + k * (ngx+1) * (ngy+1);
00489           Entity * const node = mesh.get_entity( node_type , node_id );
00490           STKUNIT_ASSERT( node != NULL );
00491           // Must be shared with 'p'
00492           STKUNIT_ASSERT( in_shared( *node , p ) );
00493           STKUNIT_ASSERT_EQUAL( in_send_ghost( *node , p ), false );
00494 
00495           //Test for coverage of comm_procs in EntityComm.cpp
00496           std::vector<unsigned> procs ;
00497     comm_procs( gg, *node , procs );
00498 
00499         }
00500       }
00501     }
00502   }
00503 
00504   mesh.modification_begin();
00505   mesh.destroy_all_ghosting();
00506   mesh.modification_end();
00507 
00508   delete[] p_box ;
00509 }
00510 
00511 //----------------------------------------------------------------------
00512 
00513 } // namespace mesh
00514 } // namespace stk
00515 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends