Sierra Toolkit  Version of the Day
UnitTestBulkModification.cpp
1 /*------------------------------------------------------------------------*/
2 /* Copyright 2010 Sandia Corporation. */
3 /* Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive */
4 /* license for use of this work by or on behalf of the U.S. Government. */
5 /* Export of this program may require a license from the */
6 /* United States Government. */
7 /*------------------------------------------------------------------------*/
8 
9 
10 #include <stk_util/unit_test_support/stk_utest_macros.hpp>
11 #include <Shards_BasicTopologies.hpp>
12 
13 #include <stk_util/parallel/Parallel.hpp>
14 
15 #include <stk_mesh/base/MetaData.hpp>
16 #include <stk_mesh/base/BulkData.hpp>
17 #include <stk_mesh/base/Entity.hpp>
18 #include <stk_mesh/base/BulkModification.hpp>
19 #include <stk_mesh/base/GetEntities.hpp>
20 #include <stk_mesh/base/Selector.hpp>
21 #include <stk_mesh/base/GetBuckets.hpp>
22 
23 #include <stk_mesh/fem/FEMMetaData.hpp>
24 
25 #include <stk_mesh/fixtures/RingFixture.hpp>
26 
27 #include <algorithm>
28 #include <stdexcept>
29 
32 using stk_classic::mesh::BucketIterator;
34 using stk_classic::mesh::EntityRank;
36 
37 class UnitTestStkMeshBulkModification {
38  public:
39  UnitTestStkMeshBulkModification(stk_classic::ParallelMachine pm) :
40  m_comm(pm),
41  m_num_procs(stk_classic::parallel_machine_size( m_comm )),
42  m_rank(stk_classic::parallel_machine_rank( m_comm )),
43  m_ring_mesh(pm)
44  { }
45 
46  void test_bulkdata_not_syncronized();
47  void test_closure_of_non_locally_used_entities();
48  void test_all_local_nodes();
49  void test_all_local_edges();
50  void test_parallel_consistency();
51 
52  BulkData& initialize_ring_fixture()
53  {
54  m_ring_mesh.m_meta_data.commit();
55  BulkData& bulk_data = m_ring_mesh.m_bulk_data;
56 
57  bulk_data.modification_begin();
58  m_ring_mesh.generate_mesh( );
59  ThrowRequire(bulk_data.modification_end());
60 
61  bulk_data.modification_begin();
62  m_ring_mesh.fixup_node_ownership( );
63  ThrowRequire(bulk_data.modification_end());
64 
65  return bulk_data;
66  }
67 
69  int m_num_procs;
70  int m_rank;
71  RingFixture m_ring_mesh;
72 };
73 
74 namespace {
75 
76 const EntityRank NODE_RANK = stk_classic::mesh::fem::FEMMetaData::NODE_RANK;
77 
78 STKUNIT_UNIT_TEST( UnitTestBulkDataNotSyrncronized , testUnit )
79 {
80  UnitTestStkMeshBulkModification unit(MPI_COMM_WORLD);
81  unit.test_bulkdata_not_syncronized();
82 }
83 
84 STKUNIT_UNIT_TEST( UnitTestClosureOfNonLocallyUsedEntities , testUnit )
85 {
86  UnitTestStkMeshBulkModification unit(MPI_COMM_WORLD);
87  unit.test_closure_of_non_locally_used_entities();
88 }
89 
90 STKUNIT_UNIT_TEST( UnitTestAllLocalNodes , testUnit )
91 {
92  UnitTestStkMeshBulkModification unit(MPI_COMM_WORLD);
93  unit.test_all_local_nodes();
94 }
95 
96 STKUNIT_UNIT_TEST( UnitTestAllLocalEdges , testUnit )
97 {
98  UnitTestStkMeshBulkModification unit(MPI_COMM_WORLD);
99  unit.test_all_local_edges();
100 }
101 
102 STKUNIT_UNIT_TEST( UnitTestParallelConsistency , testUnit )
103 {
104  UnitTestStkMeshBulkModification unit(MPI_COMM_WORLD);
105  unit.test_parallel_consistency();
106 }
107 
108 } //end namespace
109 
110 void UnitTestStkMeshBulkModification::test_bulkdata_not_syncronized()
111 {
112  BulkData& bulk_data = initialize_ring_fixture();
113 
114  bulk_data.modification_begin(); // Intentially make things unsynced
115 
116  std::vector< Entity *> entities;
117  std::vector< Entity *> entities_closure;
118  STKUNIT_ASSERT_THROW(stk_classic::mesh::find_closure(bulk_data, entities, entities_closure), std::runtime_error);
119 }
120 
121 void UnitTestStkMeshBulkModification::test_closure_of_non_locally_used_entities()
122 {
123  BulkData& bulk_data = initialize_ring_fixture();
124 
125  const stk_classic::mesh::Ghosting & ghost = bulk_data.shared_aura();
126 
127  std::vector< Entity* > ghost_receive ;
128 
129  ghost.receive_list( ghost_receive );
130 
131  if (!ghost_receive.empty()) {
132  std::vector< Entity *> entities;
133  std::vector< Entity *> entities_closure;
134 
135  entities.push_back(ghost_receive.front());
136 
137  STKUNIT_ASSERT_THROW(stk_classic::mesh::find_closure(bulk_data, entities, entities_closure), std::runtime_error);
138  }
139 }
140 
141 void UnitTestStkMeshBulkModification::test_all_local_nodes()
142 {
143  BulkData& bulk_data = initialize_ring_fixture();
144 
145  {
146  std::vector< Entity *> entities;
147  std::vector< Entity *> entities_closure;
148  find_closure(bulk_data, entities, entities_closure);
149 
150  // the closure of the an empty set of entities on all procs should be empty
151  STKUNIT_EXPECT_TRUE(entities_closure.empty());
152  }
153 
154  {
155  // Get a selector for the univeral part (contains local, shared, and ghosted)
156  const stk_classic::mesh::Part& universal = m_ring_mesh.m_meta_data.universal_part();
157  stk_classic::mesh::Selector universal_selector(universal);
158 
159  // Get the buckets that will give us the universal nodes
160  const std::vector<Bucket*>& node_buckets = bulk_data.buckets(NODE_RANK);
161  std::vector<Bucket*> buckets;
162  stk_classic::mesh::get_buckets(universal_selector, node_buckets, buckets);
163 
164  // Get the universal nodes
165  std::vector< Entity *> universal_entities;
166  for (std::vector<Bucket*>::iterator itr = buckets.begin();
167  itr != buckets.end(); ++itr) {
168  Bucket& b = **itr;
169  for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) {
170  universal_entities.push_back(&(*bitr));
171  }
172  }
173  buckets.clear();
174 
175  // sort and unique the universal nodes
176  std::sort(universal_entities.begin(), universal_entities.end(), stk_classic::mesh::EntityLess());
177  std::vector<Entity*>::iterator new_end = std::unique(universal_entities.begin(), universal_entities.end(), stk_classic::mesh::EntityEqual());
178  universal_entities.erase(new_end, universal_entities.end());
179 
180  // Get the buckets that will give us the locally used nodes
181  stk_classic::mesh::Selector locally_used_selector =
182  m_ring_mesh.m_meta_data.locally_owned_part() |
183  m_ring_mesh.m_meta_data.globally_shared_part();
184 
185  stk_classic::mesh::get_buckets(locally_used_selector, node_buckets, buckets);
186 
187  // Get the locally used nodes
188  std::vector< Entity *> entities;
189  for (std::vector<Bucket*>::iterator itr = buckets.begin();
190  itr != buckets.end(); ++itr) {
191  Bucket& b = **itr;
192  for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) {
193  entities.push_back(&(*bitr));
194  }
195  }
196 
197  // Get the closure, passing in the locally used nodes on each proc
198  std::vector< Entity *> entities_closure;
199  stk_classic::mesh::find_closure(bulk_data, entities, entities_closure);
200 
201  // The ghosted nodes on this part will be locally used on one of the other
202  // procs, so we expect that they will be part of the closure. In other
203  // words, the set of nodes returned by find_closure should exactly match
204  // the set of universal nodes.
205  STKUNIT_ASSERT_TRUE(universal_entities.size() == entities_closure.size());
206  stk_classic::mesh::EntityEqual ee;
207  for (size_t i = 0; i < entities_closure.size(); ++i) {
208  STKUNIT_EXPECT_TRUE(ee(universal_entities[i], entities_closure[i]));
209  }
210  }
211 }
212 
213 void UnitTestStkMeshBulkModification::test_all_local_edges()
214 {
215  BulkData& bulk_data = initialize_ring_fixture();
216  const stk_classic::mesh::EntityRank element_rank = m_ring_mesh.m_meta_data.element_rank();
217 
218  {
219  const stk_classic::mesh::Part& universal = m_ring_mesh.m_meta_data.universal_part();
220  stk_classic::mesh::Selector universal_selector(universal);
221 
222  const std::vector<Bucket*>& node_buckets = bulk_data.buckets(NODE_RANK);
223  const std::vector<Bucket*>& edge_buckets = bulk_data.buckets(element_rank);
224  std::vector<Bucket*> buckets;
225 
226  stk_classic::mesh::get_buckets(universal_selector, node_buckets, buckets);
227 
228  // get all the nodes that this process knows about
229  std::vector< Entity *> universal_entities;
230  for (std::vector<Bucket*>::iterator itr = buckets.begin();
231  itr != buckets.end(); ++itr) {
232  Bucket& b = **itr;
233  for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) {
234  universal_entities.push_back(&(*bitr));
235  }
236  }
237  buckets.clear();
238 
239  stk_classic::mesh::get_buckets(universal_selector, edge_buckets, buckets);
240 
241  // get all the edges that this process knows about
242  for (std::vector<Bucket*>::iterator itr = buckets.begin();
243  itr != buckets.end(); ++itr) {
244  Bucket& b = **itr;
245  for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) {
246  universal_entities.push_back(&(*bitr));
247  }
248  }
249  buckets.clear();
250 
251  // universal entities should now have all the universal nodes and edges
252  // sort and uniq the universal nodes/edges
253  std::sort(universal_entities.begin(), universal_entities.end(), stk_classic::mesh::EntityLess());
254  std::vector<Entity*>::iterator new_end = std::unique(universal_entities.begin(), universal_entities.end(), stk_classic::mesh::EntityEqual());
255  universal_entities.erase(new_end, universal_entities.end());
256 
257  // get the buckets that we need to traverse to get the locally used edges
258  stk_classic::mesh::Selector locally_used_selector =
259  m_ring_mesh.m_meta_data.locally_owned_part() |
260  m_ring_mesh.m_meta_data.globally_shared_part();
261 
262  stk_classic::mesh::get_buckets(locally_used_selector, edge_buckets, buckets);
263 
264  // get the locally used edges and store them in entities
265  std::vector< Entity *> entities;
266  for (std::vector<Bucket*>::iterator itr = buckets.begin();
267  itr != buckets.end(); ++itr) {
268  Bucket& b = **itr;
269  for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) {
270  entities.push_back(&(*bitr));
271  }
272  }
273 
274  // call find_closure, passing in the locally used edges
275  std::vector< Entity *> entities_closure;
276  stk_classic::mesh::find_closure(bulk_data, entities, entities_closure);
277 
278  // The ghosted entities on this proc (edge or node) should be contained
279  // in the closure of the locally-used edge on some other proc, so we
280  // expect that they will be part of the closure. In other
281  // words, the set of entities returned by find_closure should exactly match
282  // the set of universal entities (nodes and edges).
283  STKUNIT_ASSERT_TRUE(universal_entities.size() == entities_closure.size());
284  stk_classic::mesh::EntityEqual ee;
285  for (size_t i = 0; i < entities_closure.size(); ++i) {
286  STKUNIT_EXPECT_TRUE(ee(universal_entities[i], entities_closure[i]));
287  }
288  }
289 }
290 
291 void UnitTestStkMeshBulkModification::test_parallel_consistency()
292 {
293  BulkData& bulk_data = initialize_ring_fixture();
294 
295  stk_classic::CommBroadcast all(bulk_data.parallel(), 0);
296 
297  std::vector< Entity *> entities;
298  std::vector< Entity *> entities_closure;
299 
300  // For proc 0 only, add locally used nodes to entities, for all other
301  // procs, leave entities empty.
302  if (m_rank == 0) {
303  const std::vector<Bucket*>& node_buckets = bulk_data.buckets(NODE_RANK);
304 
305  stk_classic::mesh::Selector locally_used_selector =
306  m_ring_mesh.m_meta_data.locally_owned_part() |
307  m_ring_mesh.m_meta_data.globally_shared_part();
308 
309  std::vector<Bucket*> buckets;
310  stk_classic::mesh::get_buckets(locally_used_selector, node_buckets, buckets);
311 
312  for (std::vector<Bucket*>::iterator itr = buckets.begin();
313  itr != buckets.end(); ++itr) {
314  Bucket& b = **itr;
315  for (BucketIterator bitr = b.begin(); bitr != b.end(); ++bitr) {
316  entities.push_back(&(*bitr));
317  }
318  }
319  }
320 
321  // Call find_closure with proc 0 passing in locally-used nodes
322  stk_classic::mesh::find_closure(bulk_data, entities, entities_closure);
323 
324  // Proc 0 will broadcast the global ids of the nodes it passed to
325  // find_closure
326 
327  // pack entities for sizing
328  for (std::vector<Entity*>::const_iterator
329  ep = entities.begin() ; ep != entities.end() ; ++ep ) {
330  all.send_buffer().pack<stk_classic::mesh::EntityKey>((*ep)->key());
331  }
332 
333  all.allocate_buffer();
334 
335  // pack for real
336  for (std::vector<Entity*>::const_iterator
337  ep = entities.begin() ; ep != entities.end() ; ++ep ) {
338  all.send_buffer().pack<stk_classic::mesh::EntityKey>((*ep)->key());
339  }
340 
341  all.communicate();
342 
343  // clear-out entities and put the nodes that correspond to the keys
344  // broadcast by proc 0 into entities.
345  entities.clear();
346  stk_classic::CommBuffer& buf = all.recv_buffer();
348  while ( buf.remaining() ) {
349  buf.unpack<stk_classic::mesh::EntityKey>(k);
350  Entity * e = bulk_data.get_entity(k);
351  // If a proc is not aware of a key, that means it has no relationship
352  // with that entity, so it can ignore it.
353  if (e != NULL) {
354  entities.push_back(e);
355  }
356  }
357 
358  // sort and unique entities
359  std::sort(entities.begin(), entities.end(), stk_classic::mesh::EntityLess());
360  std::vector<Entity*>::iterator new_end = std::unique(entities.begin(), entities.end(), stk_classic::mesh::EntityEqual());
361  entities.erase(new_end, entities.end());
362 
363  // If any processor had ghosted nodes that were local to proc 0, those
364  // nodes should be in the closure because proc 0 passed them in to
365  // find_closure.
366  STKUNIT_ASSERT_TRUE(entities.size() == entities_closure.size());
367  stk_classic::mesh::EntityEqual ee;
368  for (size_t i = 0; i < entities_closure.size(); ++i) {
369  STKUNIT_EXPECT_TRUE(ee(entities[i], entities_closure[i]));
370  }
371 }
stk_classic::mesh::Bucket::end
iterator end() const
End of the bucket.
Definition: Bucket.hpp:116
stk_classic::mesh::EntityKey
Integer type for the entity keys, which is an encoding of the entity type and entity identifier.
Definition: base/EntityKey.hpp:63
stk_classic::mesh::BulkData::parallel
ParallelMachine parallel() const
The parallel machine.
Definition: BulkData.hpp:79
stk_classic::mesh::fixtures::RingFixture
Definition: RingFixture.hpp:37
stk_classic::mesh::get_buckets
AllSelectedBucketsRange get_buckets(const Selector &selector, const BulkData &mesh)
Definition: GetBuckets.cpp:26
stk_classic::mesh::Bucket
A container for the field data of a homogeneous collection of entities.
Definition: Bucket.hpp:94
stk_classic::parallel_machine_size
unsigned parallel_machine_size(ParallelMachine parallel_machine)
Member function parallel_machine_size ...
Definition: Parallel.cpp:18
stk_classic::mesh::BulkData::shared_aura
Ghosting & shared_aura() const
Query the shared-entity aura. Is likely to be stale if ownership or sharing has changed and the 'modi...
Definition: BulkData.hpp:375
stk_classic::mesh::Part
An application-defined subset of a problem domain.
Definition: Part.hpp:49
stk_classic::ParallelMachine
MPI_Comm ParallelMachine
Definition: Parallel.hpp:32
stk_classic::mesh::Bucket::begin
iterator begin() const
Beginning of the bucket.
Definition: Bucket.hpp:113
stk_classic::mesh::BulkData::get_entity
Entity * get_entity(EntityRank entity_rank, EntityId entity_id) const
Get entity with a given key.
Definition: BulkData.hpp:211
stk_classic::mesh::BulkData::modification_end
bool modification_end()
Parallel synchronization of modifications and transition to the guaranteed parallel consistent state.
Definition: BulkDataEndSync.cpp:729
stk_classic
Sierra Toolkit.
Definition: AlgorithmRunner.cpp:16
stk_classic::mesh::BulkData::modification_begin
bool modification_begin()
Begin a modification phase during which the mesh bulk data could become parallel inconsistent....
Definition: BulkData.cpp:172
stk_classic::mesh::Ghosting
Data for ghosting mesh entities.
Definition: Ghosting.hpp:28
stk_classic::mesh::Selector
This is a class for selecting buckets based on a set of meshparts and set logic.
Definition: Selector.hpp:112
stk_classic::mesh::EntityLess
Comparison operator for entities compares the entities' keys.
Definition: Entity.hpp:478
stk_classic::mesh::Ghosting::receive_list
void receive_list(std::vector< Entity * > &) const
Entities ghosted on this processor from the owner.
Definition: Ghosting.cpp:33
stk_classic::parallel_machine_rank
unsigned parallel_machine_rank(ParallelMachine parallel_machine)
Member function parallel_machine_rank ...
Definition: Parallel.cpp:29
stk_classic::mesh::Entity
A fundamental unit within the discretization of a problem domain, including but not limited to nodes,...
Definition: Entity.hpp:120
stk_classic::mesh::BulkData
Manager for an integrated collection of entities, entity relations, and buckets of field data.
Definition: BulkData.hpp:49
stk_classic::mesh::BulkData::buckets
const std::vector< Bucket * > & buckets(EntityRank rank) const
Query all buckets of a given entity rank.
Definition: BulkData.hpp:195