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/FEMMetaData.hpp>
00024 
00025 #include <stk_mesh/fixtures/RingFixture.hpp>
00026 
00027 #include <algorithm>
00028 #include <stdexcept>
00029 
00030 using stk::mesh::BulkData;
00031 using stk::mesh::Bucket;
00032 using stk::mesh::BucketIterator;
00033 using stk::mesh::Entity;
00034 using stk::mesh::EntityRank;
00035 using stk::mesh::fixtures::RingFixture;
00036 
00037 class UnitTestStkMeshBulkModification {
00038  public:
00039   UnitTestStkMeshBulkModification(stk::ParallelMachine pm) :
00040     m_comm(pm),
00041     m_num_procs(stk::parallel_machine_size( m_comm )),
00042     m_rank(stk::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::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::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::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::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::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::mesh::Part& universal = m_ring_mesh.m_meta_data.universal_part();
00157     stk::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::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::mesh::EntityLess());
00177     std::vector<Entity*>::iterator new_end = std::unique(universal_entities.begin(), universal_entities.end(), stk::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::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::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::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::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::mesh::EntityRank element_rank = m_ring_mesh.m_meta_data.element_rank();
00217 
00218   {
00219     const stk::mesh::Part& universal = m_ring_mesh.m_meta_data.universal_part();
00220     stk::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::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::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::mesh::EntityLess());
00254     std::vector<Entity*>::iterator new_end = std::unique(universal_entities.begin(), universal_entities.end(), stk::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::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::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::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::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::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::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::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::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::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::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::CommBuffer& buf = all.recv_buffer();
00347   stk::mesh::EntityKey k ;
00348   while ( buf.remaining() ) {
00349     buf.unpack<stk::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::mesh::EntityLess());
00360   std::vector<Entity*>::iterator new_end = std::unique(entities.begin(), entities.end(), stk::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::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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends