|
Sierra Toolkit
Version of the Day
|
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 <stk_util/unit_test_support/stk_utest_macros.hpp> 00011 #include <Shards_BasicTopologies.hpp> 00012 00013 #include <stk_util/parallel/Parallel.hpp> 00014 00015 #include <stk_mesh/base/MetaData.hpp> 00016 #include <stk_mesh/base/BulkData.hpp> 00017 #include <stk_mesh/base/Entity.hpp> 00018 #include <stk_mesh/base/BulkModification.hpp> 00019 #include <stk_mesh/base/GetEntities.hpp> 00020 #include <stk_mesh/base/Selector.hpp> 00021 #include <stk_mesh/base/GetBuckets.hpp> 00022 00023 #include <stk_mesh/fem/FEMMetaData.hpp> 00024 00025 #include <stk_mesh/fixtures/RingFixture.hpp> 00026 00027 #include <algorithm> 00028 #include <stdexcept> 00029 00030 using stk_classic::mesh::BulkData; 00031 using stk_classic::mesh::Bucket; 00032 using stk_classic::mesh::BucketIterator; 00033 using stk_classic::mesh::Entity; 00034 using stk_classic::mesh::EntityRank; 00035 using stk_classic::mesh::fixtures::RingFixture; 00036 00037 class UnitTestStkMeshBulkModification { 00038 public: 00039 UnitTestStkMeshBulkModification(stk_classic::ParallelMachine pm) : 00040 m_comm(pm), 00041 m_num_procs(stk_classic::parallel_machine_size( m_comm )), 00042 m_rank(stk_classic::parallel_machine_rank( m_comm )), 00043 m_ring_mesh(pm) 00044 { } 00045 00046 void test_bulkdata_not_syncronized(); 00047 void test_closure_of_non_locally_used_entities(); 00048 void test_all_local_nodes(); 00049 void test_all_local_edges(); 00050 void test_parallel_consistency(); 00051 00052 BulkData& initialize_ring_fixture() 00053 { 00054 m_ring_mesh.m_meta_data.commit(); 00055 BulkData& bulk_data = m_ring_mesh.m_bulk_data; 00056 00057 bulk_data.modification_begin(); 00058 m_ring_mesh.generate_mesh( ); 00059 ThrowRequire(bulk_data.modification_end()); 00060 00061 bulk_data.modification_begin(); 00062 m_ring_mesh.fixup_node_ownership( ); 00063 ThrowRequire(bulk_data.modification_end()); 00064 00065 return bulk_data; 00066 } 00067 00068 stk_classic::ParallelMachine m_comm; 00069 int m_num_procs; 00070 int m_rank; 00071 RingFixture m_ring_mesh; 00072 }; 00073 00074 namespace { 00075 00076 const EntityRank NODE_RANK = stk_classic::mesh::fem::FEMMetaData::NODE_RANK; 00077 00078 STKUNIT_UNIT_TEST( UnitTestBulkDataNotSyrncronized , testUnit ) 00079 { 00080 UnitTestStkMeshBulkModification unit(MPI_COMM_WORLD); 00081 unit.test_bulkdata_not_syncronized(); 00082 } 00083 00084 STKUNIT_UNIT_TEST( UnitTestClosureOfNonLocallyUsedEntities , testUnit ) 00085 { 00086 UnitTestStkMeshBulkModification unit(MPI_COMM_WORLD); 00087 unit.test_closure_of_non_locally_used_entities(); 00088 } 00089 00090 STKUNIT_UNIT_TEST( UnitTestAllLocalNodes , testUnit ) 00091 { 00092 UnitTestStkMeshBulkModification unit(MPI_COMM_WORLD); 00093 unit.test_all_local_nodes(); 00094 } 00095 00096 STKUNIT_UNIT_TEST( UnitTestAllLocalEdges , testUnit ) 00097 { 00098 UnitTestStkMeshBulkModification unit(MPI_COMM_WORLD); 00099 unit.test_all_local_edges(); 00100 } 00101 00102 STKUNIT_UNIT_TEST( UnitTestParallelConsistency , testUnit ) 00103 { 00104 UnitTestStkMeshBulkModification unit(MPI_COMM_WORLD); 00105 unit.test_parallel_consistency(); 00106 } 00107 00108 } //end namespace 00109 00110 void UnitTestStkMeshBulkModification::test_bulkdata_not_syncronized() 00111 { 00112 BulkData& bulk_data = initialize_ring_fixture(); 00113 00114 bulk_data.modification_begin(); // Intentially make things unsynced 00115 00116 std::vector< Entity *> entities; 00117 std::vector< Entity *> entities_closure; 00118 STKUNIT_ASSERT_THROW(stk_classic::mesh::find_closure(bulk_data, entities, entities_closure), std::runtime_error); 00119 } 00120 00121 void UnitTestStkMeshBulkModification::test_closure_of_non_locally_used_entities() 00122 { 00123 BulkData& bulk_data = initialize_ring_fixture(); 00124 00125 const stk_classic::mesh::Ghosting & ghost = bulk_data.shared_aura(); 00126 00127 std::vector< Entity* > ghost_receive ; 00128 00129 ghost.receive_list( ghost_receive ); 00130 00131 if (!ghost_receive.empty()) { 00132 std::vector< Entity *> entities; 00133 std::vector< Entity *> entities_closure; 00134 00135 entities.push_back(ghost_receive.front()); 00136 00137 STKUNIT_ASSERT_THROW(stk_classic::mesh::find_closure(bulk_data, entities, entities_closure), std::runtime_error); 00138 } 00139 } 00140 00141 void UnitTestStkMeshBulkModification::test_all_local_nodes() 00142 { 00143 BulkData& bulk_data = initialize_ring_fixture(); 00144 00145 { 00146 std::vector< Entity *> entities; 00147 std::vector< Entity *> entities_closure; 00148 find_closure(bulk_data, entities, entities_closure); 00149 00150 // the closure of the an empty set of entities on all procs should be empty 00151 STKUNIT_EXPECT_TRUE(entities_closure.empty()); 00152 } 00153 00154 { 00155 // Get a selector for the univeral part (contains local, shared, and ghosted) 00156 const stk_classic::mesh::Part& universal = m_ring_mesh.m_meta_data.universal_part(); 00157 stk_classic::mesh::Selector universal_selector(universal); 00158 00159 // Get the buckets that will give us the universal nodes 00160 const std::vector<Bucket*>& node_buckets = bulk_data.buckets(NODE_RANK); 00161 std::vector<Bucket*> buckets; 00162 stk_classic::mesh::get_buckets(universal_selector, node_buckets, buckets); 00163 00164 // Get the universal nodes 00165 std::vector< Entity *> universal_entities; 00166 for (std::vector<Bucket*>::iterator itr = buckets.begin(); 00167 itr != buckets.end(); ++itr) { 00168 Bucket& b = **itr; 00169 for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) { 00170 universal_entities.push_back(&(*bitr)); 00171 } 00172 } 00173 buckets.clear(); 00174 00175 // sort and unique the universal nodes 00176 std::sort(universal_entities.begin(), universal_entities.end(), stk_classic::mesh::EntityLess()); 00177 std::vector<Entity*>::iterator new_end = std::unique(universal_entities.begin(), universal_entities.end(), stk_classic::mesh::EntityEqual()); 00178 universal_entities.erase(new_end, universal_entities.end()); 00179 00180 // Get the buckets that will give us the locally used nodes 00181 stk_classic::mesh::Selector locally_used_selector = 00182 m_ring_mesh.m_meta_data.locally_owned_part() | 00183 m_ring_mesh.m_meta_data.globally_shared_part(); 00184 00185 stk_classic::mesh::get_buckets(locally_used_selector, node_buckets, buckets); 00186 00187 // Get the locally used nodes 00188 std::vector< Entity *> entities; 00189 for (std::vector<Bucket*>::iterator itr = buckets.begin(); 00190 itr != buckets.end(); ++itr) { 00191 Bucket& b = **itr; 00192 for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) { 00193 entities.push_back(&(*bitr)); 00194 } 00195 } 00196 00197 // Get the closure, passing in the locally used nodes on each proc 00198 std::vector< Entity *> entities_closure; 00199 stk_classic::mesh::find_closure(bulk_data, entities, entities_closure); 00200 00201 // The ghosted nodes on this part will be locally used on one of the other 00202 // procs, so we expect that they will be part of the closure. In other 00203 // words, the set of nodes returned by find_closure should exactly match 00204 // the set of universal nodes. 00205 STKUNIT_ASSERT_TRUE(universal_entities.size() == entities_closure.size()); 00206 stk_classic::mesh::EntityEqual ee; 00207 for (size_t i = 0; i < entities_closure.size(); ++i) { 00208 STKUNIT_EXPECT_TRUE(ee(universal_entities[i], entities_closure[i])); 00209 } 00210 } 00211 } 00212 00213 void UnitTestStkMeshBulkModification::test_all_local_edges() 00214 { 00215 BulkData& bulk_data = initialize_ring_fixture(); 00216 const stk_classic::mesh::EntityRank element_rank = m_ring_mesh.m_meta_data.element_rank(); 00217 00218 { 00219 const stk_classic::mesh::Part& universal = m_ring_mesh.m_meta_data.universal_part(); 00220 stk_classic::mesh::Selector universal_selector(universal); 00221 00222 const std::vector<Bucket*>& node_buckets = bulk_data.buckets(NODE_RANK); 00223 const std::vector<Bucket*>& edge_buckets = bulk_data.buckets(element_rank); 00224 std::vector<Bucket*> buckets; 00225 00226 stk_classic::mesh::get_buckets(universal_selector, node_buckets, buckets); 00227 00228 // get all the nodes that this process knows about 00229 std::vector< Entity *> universal_entities; 00230 for (std::vector<Bucket*>::iterator itr = buckets.begin(); 00231 itr != buckets.end(); ++itr) { 00232 Bucket& b = **itr; 00233 for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) { 00234 universal_entities.push_back(&(*bitr)); 00235 } 00236 } 00237 buckets.clear(); 00238 00239 stk_classic::mesh::get_buckets(universal_selector, edge_buckets, buckets); 00240 00241 // get all the edges that this process knows about 00242 for (std::vector<Bucket*>::iterator itr = buckets.begin(); 00243 itr != buckets.end(); ++itr) { 00244 Bucket& b = **itr; 00245 for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) { 00246 universal_entities.push_back(&(*bitr)); 00247 } 00248 } 00249 buckets.clear(); 00250 00251 // universal entities should now have all the universal nodes and edges 00252 // sort and uniq the universal nodes/edges 00253 std::sort(universal_entities.begin(), universal_entities.end(), stk_classic::mesh::EntityLess()); 00254 std::vector<Entity*>::iterator new_end = std::unique(universal_entities.begin(), universal_entities.end(), stk_classic::mesh::EntityEqual()); 00255 universal_entities.erase(new_end, universal_entities.end()); 00256 00257 // get the buckets that we need to traverse to get the locally used edges 00258 stk_classic::mesh::Selector locally_used_selector = 00259 m_ring_mesh.m_meta_data.locally_owned_part() | 00260 m_ring_mesh.m_meta_data.globally_shared_part(); 00261 00262 stk_classic::mesh::get_buckets(locally_used_selector, edge_buckets, buckets); 00263 00264 // get the locally used edges and store them in entities 00265 std::vector< Entity *> entities; 00266 for (std::vector<Bucket*>::iterator itr = buckets.begin(); 00267 itr != buckets.end(); ++itr) { 00268 Bucket& b = **itr; 00269 for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) { 00270 entities.push_back(&(*bitr)); 00271 } 00272 } 00273 00274 // call find_closure, passing in the locally used edges 00275 std::vector< Entity *> entities_closure; 00276 stk_classic::mesh::find_closure(bulk_data, entities, entities_closure); 00277 00278 // The ghosted entities on this proc (edge or node) should be contained 00279 // in the closure of the locally-used edge on some other proc, so we 00280 // expect that they will be part of the closure. In other 00281 // words, the set of entities returned by find_closure should exactly match 00282 // the set of universal entities (nodes and edges). 00283 STKUNIT_ASSERT_TRUE(universal_entities.size() == entities_closure.size()); 00284 stk_classic::mesh::EntityEqual ee; 00285 for (size_t i = 0; i < entities_closure.size(); ++i) { 00286 STKUNIT_EXPECT_TRUE(ee(universal_entities[i], entities_closure[i])); 00287 } 00288 } 00289 } 00290 00291 void UnitTestStkMeshBulkModification::test_parallel_consistency() 00292 { 00293 BulkData& bulk_data = initialize_ring_fixture(); 00294 00295 stk_classic::CommBroadcast all(bulk_data.parallel(), 0); 00296 00297 std::vector< Entity *> entities; 00298 std::vector< Entity *> entities_closure; 00299 00300 // For proc 0 only, add locally used nodes to entities, for all other 00301 // procs, leave entities empty. 00302 if (m_rank == 0) { 00303 const std::vector<Bucket*>& node_buckets = bulk_data.buckets(NODE_RANK); 00304 00305 stk_classic::mesh::Selector locally_used_selector = 00306 m_ring_mesh.m_meta_data.locally_owned_part() | 00307 m_ring_mesh.m_meta_data.globally_shared_part(); 00308 00309 std::vector<Bucket*> buckets; 00310 stk_classic::mesh::get_buckets(locally_used_selector, node_buckets, buckets); 00311 00312 for (std::vector<Bucket*>::iterator itr = buckets.begin(); 00313 itr != buckets.end(); ++itr) { 00314 Bucket& b = **itr; 00315 for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) { 00316 entities.push_back(&(*bitr)); 00317 } 00318 } 00319 } 00320 00321 // Call find_closure with proc 0 passing in locally-used nodes 00322 stk_classic::mesh::find_closure(bulk_data, entities, entities_closure); 00323 00324 // Proc 0 will broadcast the global ids of the nodes it passed to 00325 // find_closure 00326 00327 // pack entities for sizing 00328 for (std::vector<Entity*>::const_iterator 00329 ep = entities.begin() ; ep != entities.end() ; ++ep ) { 00330 all.send_buffer().pack<stk_classic::mesh::EntityKey>((*ep)->key()); 00331 } 00332 00333 all.allocate_buffer(); 00334 00335 // pack for real 00336 for (std::vector<Entity*>::const_iterator 00337 ep = entities.begin() ; ep != entities.end() ; ++ep ) { 00338 all.send_buffer().pack<stk_classic::mesh::EntityKey>((*ep)->key()); 00339 } 00340 00341 all.communicate(); 00342 00343 // clear-out entities and put the nodes that correspond to the keys 00344 // broadcast by proc 0 into entities. 00345 entities.clear(); 00346 stk_classic::CommBuffer& buf = all.recv_buffer(); 00347 stk_classic::mesh::EntityKey k ; 00348 while ( buf.remaining() ) { 00349 buf.unpack<stk_classic::mesh::EntityKey>(k); 00350 Entity * e = bulk_data.get_entity(k); 00351 // If a proc is not aware of a key, that means it has no relationship 00352 // with that entity, so it can ignore it. 00353 if (e != NULL) { 00354 entities.push_back(e); 00355 } 00356 } 00357 00358 // sort and unique entities 00359 std::sort(entities.begin(), entities.end(), stk_classic::mesh::EntityLess()); 00360 std::vector<Entity*>::iterator new_end = std::unique(entities.begin(), entities.end(), stk_classic::mesh::EntityEqual()); 00361 entities.erase(new_end, entities.end()); 00362 00363 // If any processor had ghosted nodes that were local to proc 0, those 00364 // nodes should be in the closure because proc 0 passed them in to 00365 // find_closure. 00366 STKUNIT_ASSERT_TRUE(entities.size() == entities_closure.size()); 00367 stk_classic::mesh::EntityEqual ee; 00368 for (size_t i = 0; i < entities_closure.size(); ++i) { 00369 STKUNIT_EXPECT_TRUE(ee(entities[i], entities_closure[i])); 00370 } 00371 }