|
Sierra Toolkit
Version of the Day
|
00001 /*------------------------------------------------------------------------*/ 00002 /* Copyright 2010, 2011 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 <stk_util/parallel/Parallel.hpp> 00011 #include <stk_util/parallel/ParallelReduce.hpp> 00012 #include <stk_util/unit_test_support/stk_utest_macros.hpp> 00013 00014 #include <stk_mesh/base/Types.hpp> 00015 #include <stk_mesh/base/MetaData.hpp> 00016 #include <stk_mesh/base/BulkData.hpp> 00017 #include <stk_mesh/base/FieldData.hpp> 00018 00019 #include <stk_mesh/fem/CoordinateSystems.hpp> 00020 #include <stk_mesh/fem/FEMMetaData.hpp> 00021 #include <stk_mesh/fem/FEMHelpers.hpp> 00022 00023 // relevant headers 00024 #include <stk_rebalance/Rebalance.hpp> 00025 #include <stk_rebalance/Partition.hpp> 00026 #include <stk_rebalance_utils/RebalanceUtils.hpp> 00027 // end relevant headers 00028 00029 static const size_t NODE_RANK = stk_classic::mesh::fem::FEMMetaData::NODE_RANK; 00030 00031 typedef stk_classic::mesh::Field<double> ScalarField ; 00032 typedef stk_classic::mesh::Field<double, stk_classic::mesh::Cartesian> VectorField ; 00033 00034 static const int spatial_dimension = 2; 00035 00036 enum { nx = 2, ny = 2 }; 00037 00038 class MockPartition : public stk_classic::rebalance::Partition 00039 { 00040 public: 00041 00042 enum BALANCE_TEST_STEP 00043 { FIRST, 00044 SECOND, 00045 THIRD }; 00046 00047 MockPartition( stk_classic::mesh::fem::FEMMetaData & fmd, stk_classic::mesh::BulkData & bd ) : 00048 stk_classic::rebalance::Partition(bd.parallel()), 00049 m_fem_meta(fmd), 00050 m_bulk_data(bd), 00051 m_step(FIRST) 00052 { } 00053 00054 ~MockPartition() { } 00055 00056 void set_balance_step(BALANCE_TEST_STEP step) 00057 { m_step = step; } 00058 00059 void set_mesh_info ( const std::vector<stk_classic::mesh::Entity *> &mesh_entities, 00060 const VectorField * nodal_coord_ref, 00061 const ScalarField * elem_weight_ref) 00062 { total_number_entities_ = mesh_entities.size(); } 00063 00064 unsigned num_elems() const 00065 { return total_number_entities_; } 00066 00067 void determine_new_partition(bool &RebalancingNeeded) 00068 { RebalancingNeeded = (m_bulk_data.parallel_size() > 1); } 00069 00070 int get_new_partition(std::vector<stk_classic::mesh::EntityProc> &new_partition); 00071 00072 bool partition_dependents_needed() const 00073 { return false; /* I handle both element and dependent node partitioning */ } 00074 00075 private: 00076 00077 unsigned total_number_entities_; 00078 stk_classic::mesh::fem::FEMMetaData & m_fem_meta; 00079 stk_classic::mesh::BulkData & m_bulk_data; 00080 BALANCE_TEST_STEP m_step; 00081 }; 00082 00083 int 00084 MockPartition::get_new_partition(std::vector<stk_classic::mesh::EntityProc> &new_partition) 00085 { 00086 const unsigned p_size = m_bulk_data.parallel_size(); 00087 const unsigned p_rank = m_bulk_data.parallel_rank(); 00088 const stk_classic::mesh::EntityRank element_rank = m_fem_meta.element_rank(); 00089 00090 new_partition.clear(); 00091 00092 if ( 1 < p_size ) { 00093 00094 if( FIRST == m_step ) 00095 { 00096 if ( p_rank == 0 ) { 00097 if ( p_size == 3 ) { 00098 const unsigned nnx = nx + 1 ; 00099 const unsigned nny = ny + 1 ; 00100 for ( unsigned iy = nny / 2 ; iy < nny ; ++iy ) { 00101 for ( unsigned ix = 0 ; ix < nnx ; ++ix ) { 00102 stk_classic::mesh::EntityId id = 1 + ix + iy * nnx ; 00103 unsigned proc = ix < nx/2 ? 1 : 2; 00104 stk_classic::mesh::EntityProc tmp( m_bulk_data.get_entity( NODE_RANK , id ) , proc ); 00105 new_partition.push_back( tmp ); 00106 } 00107 } 00108 for ( unsigned iy = ny / 2 ; iy < ny ; ++iy ) { 00109 for ( unsigned ix = 0 ; ix < nx ; ++ix ) { 00110 stk_classic::mesh::EntityId id = 1 + ix + iy * nx ; 00111 unsigned proc = ix < nx/2 ? 1 : 2; 00112 stk_classic::mesh::EntityProc tmp( m_bulk_data.get_entity( element_rank , id ) , proc ); 00113 new_partition.push_back( tmp ); 00114 } 00115 } 00116 } 00117 else 00118 { 00119 const unsigned nnx = nx + 1 ; 00120 const unsigned nny = ny + 1 ; 00121 for ( unsigned iy = nny / 2 ; iy < nny ; ++iy ) { 00122 for ( unsigned ix = 0 ; ix < nnx ; ++ix ) { 00123 stk_classic::mesh::EntityId id = 1 + ix + iy * nnx ; 00124 stk_classic::mesh::EntityProc tmp( m_bulk_data.get_entity( NODE_RANK , id ) , 1 ); 00125 new_partition.push_back( tmp ); 00126 } 00127 } 00128 for ( unsigned iy = ny / 2 ; iy < ny ; ++iy ) { 00129 for ( unsigned ix = 0 ; ix < nx ; ++ix ) { 00130 stk_classic::mesh::EntityId id = 1 + ix + iy * nx ; 00131 stk_classic::mesh::EntityProc tmp( m_bulk_data.get_entity( element_rank , id ) , 1 ); 00132 new_partition.push_back( tmp ); 00133 } 00134 } 00135 } 00136 } 00137 } 00138 00139 else if( SECOND == m_step ) 00140 { 00141 if ( p_rank == 0 ) { 00142 const unsigned nnx = nx + 1 ; 00143 const unsigned nny = ny + 1 ; 00144 for ( unsigned iy = 0 ; iy < nny / 2 ; ++iy ) { 00145 for ( unsigned ix = 0 ; ix < nnx ; ++ix ) { 00146 stk_classic::mesh::EntityId id = 1 + ix + iy * nnx ; 00147 stk_classic::mesh::EntityProc tmp( m_bulk_data.get_entity( NODE_RANK , id ) , 1 ); 00148 new_partition.push_back( tmp ); 00149 } 00150 } 00151 for ( unsigned iy = 0 ; iy < ny / 2 ; ++iy ) { 00152 for ( unsigned ix = 0 ; ix < nx ; ++ix ) { 00153 stk_classic::mesh::EntityId id = 1 + ix + iy * nx ; 00154 stk_classic::mesh::EntityProc tmp( m_bulk_data.get_entity( element_rank , id ) , 1 ); 00155 new_partition.push_back( tmp ); 00156 } 00157 } 00158 } 00159 } 00160 00161 else if( THIRD == m_step ) 00162 { 00163 if ( p_size == 3 ) { 00164 new_partition.clear(); 00165 00166 if ( p_rank == 2 ) { 00167 const unsigned nnx = nx + 1 ; 00168 const unsigned nny = ny + 1 ; 00169 for ( unsigned iy = nny / 2 ; iy < nny ; ++iy ) { 00170 for ( unsigned ix = nx / 2 ; ix < nnx ; ++ix ) { 00171 stk_classic::mesh::EntityId id = 1 + ix + iy * nnx ; 00172 unsigned proc = 1; 00173 stk_classic::mesh::EntityProc tmp( m_bulk_data.get_entity( NODE_RANK , id ) , proc ); 00174 new_partition.push_back( tmp ); 00175 } 00176 } 00177 for ( unsigned iy = ny / 2 ; iy < ny ; ++iy ) { 00178 for ( unsigned ix = nx / 2 ; ix < nx ; ++ix ) { 00179 stk_classic::mesh::EntityId id = 1 + ix + iy * nx ; 00180 unsigned proc = 1; 00181 stk_classic::mesh::EntityProc tmp( m_bulk_data.get_entity( element_rank , id ) , proc ); 00182 new_partition.push_back( tmp ); 00183 } 00184 } 00185 } 00186 } 00187 } 00188 } 00189 00190 return 0; 00191 } 00192 00193 00194 STKUNIT_UNIT_TEST(UnitTestRebalanceSimple, testUnit) 00195 { 00196 #ifdef STK_HAS_MPI 00197 stk_classic::ParallelMachine comm(MPI_COMM_WORLD); 00198 #else 00199 stk_classic::ParallelMachine comm(0); 00200 #endif 00201 00202 unsigned spatial_dimension = 2; 00203 stk_classic::mesh::fem::FEMMetaData fem_meta; 00204 fem_meta.FEM_initialize(spatial_dimension, stk_classic::mesh::fem::entity_rank_names(spatial_dimension) ); 00205 stk_classic::mesh::MetaData & meta_data = stk_classic::mesh::fem::FEMMetaData::get_meta_data(fem_meta); 00206 stk_classic::mesh::BulkData bulk_data( meta_data , comm , 100 ); 00207 const stk_classic::mesh::EntityRank element_rank = fem_meta.element_rank(); 00208 stk_classic::mesh::fem::CellTopology quad_top(shards::getCellTopologyData<shards::Quadrilateral<4> >()); 00209 stk_classic::mesh::Part & quad_part( fem_meta.declare_part("quad", quad_top ) ); 00210 VectorField & coord_field( fem_meta.declare_field< VectorField >( "coordinates" ) ); 00211 ScalarField & weight_field( fem_meta.declare_field< ScalarField >( "element_weights" ) ); 00212 00213 stk_classic::mesh::put_field( coord_field , NODE_RANK , fem_meta.universal_part() ); 00214 stk_classic::mesh::put_field(weight_field , element_rank , fem_meta.universal_part() ); 00215 00216 fem_meta.commit(); 00217 00218 const unsigned p_size = bulk_data.parallel_size(); 00219 const unsigned p_rank = bulk_data.parallel_rank(); 00220 00221 // create initial mesh 00222 bulk_data.modification_begin(); 00223 00224 if ( p_rank == 0 ) { 00225 const unsigned nnx = nx + 1 ; 00226 for ( unsigned iy = 0 ; iy < ny ; ++iy ) { 00227 for ( unsigned ix = 0 ; ix < nx ; ++ix ) { 00228 stk_classic::mesh::EntityId elem = 1 + ix + iy * nx ; 00229 stk_classic::mesh::EntityId nodes[4] ; 00230 nodes[0] = 1 + ix + iy * nnx ; 00231 nodes[1] = 2 + ix + iy * nnx ; 00232 nodes[2] = 2 + ix + ( iy + 1 ) * nnx ; 00233 nodes[3] = 1 + ix + ( iy + 1 ) * nnx ; 00234 00235 stk_classic::mesh::fem::declare_element( bulk_data , quad_part , elem , nodes ); 00236 } 00237 } 00238 // end create initial mesh 00239 00240 // assign element weights 00241 for ( unsigned iy = 0 ; iy < ny ; ++iy ) { 00242 for ( unsigned ix = 0 ; ix < nx ; ++ix ) { 00243 stk_classic::mesh::EntityId elem = 1 + ix + iy * nx ; 00244 stk_classic::mesh::Entity * e = bulk_data.get_entity( element_rank, elem ); 00245 double * const e_weight = stk_classic::mesh::field_data( weight_field , *e ); 00246 *e_weight = 1.0; 00247 } 00248 } 00249 // end assign element weights 00250 } 00251 00252 // Only P0 has any nodes or elements 00253 if ( p_rank == 0 ) { 00254 STKUNIT_ASSERT( ! bulk_data.buckets( NODE_RANK ).empty() ); 00255 STKUNIT_ASSERT( ! bulk_data.buckets( element_rank ).empty() ); 00256 } 00257 else { 00258 STKUNIT_ASSERT( bulk_data.buckets( NODE_RANK ).empty() ); 00259 STKUNIT_ASSERT( bulk_data.buckets( element_rank ).empty() ); 00260 } 00261 00262 bulk_data.modification_end(); 00263 00264 // Create our Partition and Selector objects 00265 MockPartition partition(fem_meta, bulk_data); 00266 stk_classic::mesh::Selector selector(fem_meta.universal_part()); 00267 00268 partition.set_balance_step(MockPartition::FIRST); 00269 // Exercise the threshhold calculation by using imblance_threshhold > 1.0 00270 bool do_rebal = 1.5 < stk_classic::rebalance::check_balance(bulk_data, &weight_field, element_rank); 00271 if( do_rebal ) 00272 { 00273 // Pick a few values as negative to exercise a check in rebalance::rebalance(...) 00274 // which converts negative weights to 1.0 00275 if ( p_rank == 0 ) 00276 { 00277 for ( unsigned iy = 0 ; iy < ny ; ++iy ) 00278 { 00279 stk_classic::mesh::EntityId elem = 1 + iy * nx ; 00280 stk_classic::mesh::Entity * e = bulk_data.get_entity( element_rank, elem ); 00281 double * const e_weight = stk_classic::mesh::field_data( weight_field , *e ); 00282 *e_weight = -2.0; 00283 } 00284 } 00285 // Do the actual rebalance 00286 stk_classic::rebalance::rebalance(bulk_data, selector, NULL, &weight_field, partition); 00287 } 00288 00289 partition.set_balance_step(MockPartition::SECOND); 00290 stk_classic::rebalance::rebalance(bulk_data, selector, NULL, &weight_field, partition); 00291 00292 partition.set_balance_step(MockPartition::THIRD); 00293 stk_classic::rebalance::rebalance(bulk_data, selector, NULL, &weight_field, partition); 00294 00295 if ( 1 < p_size ) { 00296 // Only P1 has any nodes or elements 00297 if ( p_rank == 1 ) { 00298 STKUNIT_ASSERT( ! bulk_data.buckets( NODE_RANK ).empty() ); 00299 STKUNIT_ASSERT( ! bulk_data.buckets( element_rank ).empty() ); 00300 } 00301 else { 00302 STKUNIT_ASSERT( bulk_data.buckets( NODE_RANK ).empty() ); 00303 STKUNIT_ASSERT( bulk_data.buckets( element_rank ).empty() ); 00304 } 00305 } 00306 } 00307