Sierra Toolkit Version of the Day
UnitTestBulkModification.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 <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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends