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