Sierra Toolkit  Version of the Day
UnitTestRelation.cpp
1 /*------------------------------------------------------------------------*/
2 /* Copyright 2010, 2011 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 #include <sstream>
10 #include <stdexcept>
11 #include <iostream>
12 
13 #include <stk_util/unit_test_support/stk_utest_macros.hpp>
14 
15 #include <stk_util/parallel/Parallel.hpp>
16 
17 #include <stk_mesh/base/BulkData.hpp>
18 #include <stk_mesh/base/GetEntities.hpp>
19 #include <stk_mesh/base/Field.hpp>
20 #include <stk_mesh/base/FieldData.hpp>
21 #include <stk_mesh/base/Comm.hpp>
22 #include <stk_mesh/base/EntityComm.hpp>
23 #include <stk_mesh/base/Ghosting.hpp>
24 
25 #include <stk_mesh/fem/FEMMetaData.hpp>
26 
27 #include <stk_mesh/fixtures/BoxFixture.hpp>
28 #include <stk_mesh/fixtures/RingFixture.hpp>
29 
30 #include <unit_tests/UnitTestModificationEndWrapper.hpp>
31 
32 #include <Shards_BasicTopologies.hpp>
33 
35 using stk_classic::mesh::EntityRank;
36 using stk_classic::mesh::EntityVector;
40 using stk_classic::mesh::EntityId;
46 
47 namespace {
48 
49 const EntityRank NODE_RANK = FEMMetaData::NODE_RANK;
50 
51 STKUNIT_UNIT_TEST(UnitTestingOfRelation, testRelation)
52 {
53  (void)test_info_;
54  // Unit test the Part functionality in isolation:
55 
56  stk_classic::ParallelMachine pm = MPI_COMM_WORLD;
57  MPI_Barrier ( MPI_COMM_WORLD );
58 
60  // static const char method[] = "stk_classic::mesh::UnitTestRelation" ;
61 
62  std::vector<std::string> entity_names(10);
63  for ( size_t i = 0 ; i < 10 ; ++i ) {
64  std::ostringstream name ;
65  name << "EntityRank" << i ;
66  entity_names[i] = name.str();
67  }
68 
69  unsigned max_bucket_size = 4;
70 
71  BoxFixture fixture1(pm , max_bucket_size, entity_names),
72  fixture2(pm , max_bucket_size, entity_names);
73 
74  FEMMetaData& meta = fixture1.fem_meta();
75  FEMMetaData& meta2 = fixture2.fem_meta();
76  const int spatial_dimension = 3;
77  const EntityRank element_rank = meta.element_rank();
78 
79  BulkData& bulk = fixture1.bulk_data();
80  BulkData& bulk2 = fixture2.bulk_data();
81 
82  ScalarFieldType & temperature =
83  meta.declare_field < ScalarFieldType > ( "temperature" , 4 );
84  ScalarFieldType & volume =
85  meta.declare_field < ScalarFieldType > ( "volume" , 4 );
86  ScalarFieldType & temperature2 =
87  meta2.declare_field < ScalarFieldType > ( "temperature" , 4 );
88  ScalarFieldType & volume2 =
89  meta2.declare_field < ScalarFieldType > ( "volume" , 4 );
90 
91  Part & universal = meta.universal_part ();
92  Part & universal2 = meta2.universal_part ();
93  Part & owned = meta.locally_owned_part ();
94 
95  stk_classic::mesh::put_field ( temperature , NODE_RANK , universal );
96  stk_classic::mesh::put_field ( volume , element_rank , universal );
97  meta.commit();
98  stk_classic::mesh::put_field ( temperature2 , NODE_RANK , universal2 );
99  stk_classic::mesh::put_field ( volume2 , element_rank , universal2 );
100 
101  meta2.commit();
102 
103  bulk.modification_begin();
104  bulk2.modification_begin();
105 
106  const int root_box[3][2] = { { 0,4 } , { 0,5 } , { 0,6 } };
107  int local_box1[3][2] = { { 0,0 } , { 0,0 } , { 0,0 } };
108  int local_box2[3][2] = { { 0,0 } , { 0,0 } , { 0,0 } };
109 
110  {
111  bulk.modification_begin();
112  fixture1.generate_boxes(root_box, local_box1);
113 
114  const Ghosting & gg = bulk.create_ghosting( std::string("shared") );
115 
116  // Test for coverage of comm_procs in EntityComm.cpp
117  EntityVector nodes;
118  stk_classic::mesh::get_entities(bulk, NODE_RANK, nodes);
119  std::vector<unsigned> procs ;
120  STKUNIT_ASSERT(!nodes.empty());
121  stk_classic::mesh::comm_procs( gg, *nodes.front() , procs );
122 
123  STKUNIT_ASSERT(bulk.modification_end());
124 
125  bulk.modification_begin();
126  bulk.destroy_all_ghosting();
127  STKUNIT_ASSERT(bulk.modification_end());
128  }
129 
130  {
131  bulk2.modification_begin();
132  fixture2.generate_boxes(root_box, local_box2);
133 
134  bulk2.create_ghosting( std::string("shared") );
135 
136  STKUNIT_ASSERT(bulk2.modification_end());
137 
138  bulk2.modification_begin();
139  bulk2.destroy_all_ghosting();
140  STKUNIT_ASSERT(bulk2.modification_end());
141  }
142 
143  Entity &cell = *(bulk.buckets (3)[0]->begin());
144  Entity &node = bulk.buckets (0)[0]-> operator [] ( 0 );
145  Entity &nodeb = bulk.buckets (0)[0]-> operator [] ( 2 );
146 
147  std::vector<Part *> parts;
148  parts.push_back ( &universal );
149  parts.push_back ( &owned );
150  bulk.modification_begin();
151  stk_classic::mesh::EntityId new_id = bulk.parallel_rank() + 1;
152  Entity &edge = bulk.declare_entity ( 1 , new_id , parts );
153 
154  Entity &cell2 = *(bulk2.buckets (3)[0]->begin());
155  Entity &node2 = *(bulk2.buckets (0)[0]->begin());
156 
157  STKUNIT_ASSERT_THROW ( bulk.declare_relation ( node , cell , 0 ) , std::runtime_error );
158  STKUNIT_ASSERT_THROW ( bulk.declare_relation ( cell , node2 , 0 ) , std::runtime_error );
159  STKUNIT_ASSERT_THROW ( bulk.declare_relation ( cell2 , node , 0 ) , std::runtime_error );
160 
161  bulk.declare_relation ( edge , node , 1 );
162  STKUNIT_ASSERT_THROW ( bulk.declare_relation ( edge , nodeb , 1 ) , std::runtime_error );
163  bulk.declare_relation ( edge , nodeb , 2 );
164 
165  std::stringstream s;
166  s << *edge.relations().first ;
167 
168  bulk.modification_end();
169 
170  //Testing on in_send_ghost and in_shared in EntityComm.cpp
171  enum { nPerProc = 10 };
172  const unsigned p_rank = stk_classic::parallel_machine_rank( pm );
173  const unsigned p_size = stk_classic::parallel_machine_size( pm );
174 
175  const unsigned nLocalEdge = nPerProc ;
176  FEMMetaData meta3( spatial_dimension );
177 
178  meta3.commit();
179 
180  Selector select_owned( meta3.locally_owned_part() );
181  Selector select_used = meta3.locally_owned_part() ;
182  Selector select_all( meta3.universal_part() );
183 
185 
186  std::vector<unsigned> local_count ;
187 
188  //------------------------------
189  { // No ghosting
190  bool aura_flag = false;
191  RingFixture mesh2( pm , nPerProc , false /* No edge parts */ );
192  mesh2.m_meta_data.commit();
193 
194  mesh2.m_bulk_data.modification_begin();
195  mesh2.generate_mesh( );
196  STKUNIT_ASSERT(stk_classic::unit_test::modification_end_wrapper(mesh2.m_bulk_data,
197  aura_flag));
198  mesh2.m_bulk_data.modification_begin();
199  mesh2.fixup_node_ownership( );
200  STKUNIT_ASSERT(stk_classic::unit_test::modification_end_wrapper(mesh2.m_bulk_data,
201  aura_flag));
202 
203  // This process' first element in the loop
204  // if a parallel mesh has a shared node
205 
206  Entity * edgenew = mesh2.m_bulk_data.get_entity( 1 , mesh2.m_edge_ids[ nLocalEdge * p_rank ] );
207 
208  mesh2.m_bulk_data.modification_begin();
209  for ( unsigned p = 0 ; p < p_size ; ++p ) if ( p != p_rank ) {
210  STKUNIT_ASSERT_EQUAL( in_shared( *edgenew , p ), false );
211  STKUNIT_ASSERT_EQUAL( in_send_ghost( *edgenew , p ), false );
212  }
213 
214  Entity * edgenew2 = mesh2.m_bulk_data.get_entity( 1 , mesh2.m_edge_ids[ nLocalEdge * p_rank ] );
215  STKUNIT_ASSERT_EQUAL( in_send_ghost( *edgenew2 , p_rank+100 ), false );
216 
217  Entity * node3 = mesh2.m_bulk_data.get_entity( 0 , mesh2.m_node_ids[ nLocalEdge * p_rank ] );
218  STKUNIT_ASSERT_EQUAL( in_shared( *node3 , p_rank+100 ), false );
219  }
220 
221  { //ghosting
222 
223  if ( 1 < p_size ) { // With ghosting
224  RingFixture mesh3( pm , nPerProc , false /* No edge parts */ );
225  mesh3.m_meta_data.commit();
226 
227  mesh3.m_bulk_data.modification_begin();
228  mesh3.generate_mesh();
229  STKUNIT_ASSERT(mesh3.m_bulk_data.modification_end());
230 
231  mesh3.m_bulk_data.modification_begin();
232  mesh3.fixup_node_ownership();
233  STKUNIT_ASSERT(mesh3.m_bulk_data.modification_end());
234 
235  const unsigned nNotOwned = nPerProc * p_rank ;
236 
237  // The not-owned shared entity:
238  Entity * node3 = mesh3.m_bulk_data.get_entity( 0 , mesh3.m_node_ids[ nNotOwned ] );
239  Entity * node4 = mesh3.m_bulk_data.get_entity( 0 , mesh3.m_node_ids[ nNotOwned ] );
240 
241  //EntityId node_edge_ids[2] ;
242  //node_edge_ids[0] = node3->relations()[0].entity()->identifier();
243  //node_edge_ids[1] = node3->relations()[1].entity()->identifier();
244 
245  mesh3.m_bulk_data.modification_begin();
246 
247  for ( unsigned p = 0 ; p < p_size ; ++p ) if ( p != p_rank ) {
248  //FIXME for Carol the check below did not pass for -np 3 or 4
249  //STKUNIT_ASSERT_EQUAL( in_shared( *node3 , p ), true );
250  STKUNIT_ASSERT_EQUAL( in_send_ghost( *node3 , p ), false );
251  }
252 
253  //not owned and not shared
254  Entity * node5 = mesh3.m_bulk_data.get_entity( 0 , mesh3.m_node_ids[ nLocalEdge * p_rank ] );
255 
256  //node_edge_ids[0] = node5->relations()[0].entity()->identifier();
257  //node_edge_ids[1] = node5->relations()[1].entity()->identifier();
258 
259  STKUNIT_ASSERT_EQUAL( in_shared( *node5 , p_rank+100 ), false );
260  STKUNIT_ASSERT_EQUAL( in_send_ghost( *node4 , p_rank+100 ), false );
261  }
262 
263  }
264 
265 }
266 
267 STKUNIT_UNIT_TEST(UnitTestingOfRelation, testDegenerateRelation)
268 {
269  (void)test_info_;
270  // Test that, if you set up degenerate relations, only of the relations
271  // is deleted when you destroy one of the degenerate relations.
272  // BulkData::destroy_relation has been changed to take a relation-id so
273  // that it can work this way.
274  //
275  // To test this, we set up an element that has several relations
276  // to the same node and then delete them one by one.
277 
278  stk_classic::ParallelMachine pm = MPI_COMM_WORLD;
279  MPI_Barrier( MPI_COMM_WORLD );
280 
281  // Set up meta and bulk data
282  const unsigned spatial_dim = 2;
283  FEMMetaData meta_data(spatial_dim);
284  meta_data.commit();
285  BulkData mesh(FEMMetaData::get_meta_data(meta_data), pm);
286  unsigned p_rank = mesh.parallel_rank();
287 
288  // Begin modification cycle so we can create the entities and relations
289  mesh.modification_begin();
290 
291  // We're just going to add everything to the universal part
292  stk_classic::mesh::PartVector empty_parts;
293 
294  // Create element
295  const EntityRank entity_rank = meta_data.element_rank();
296  Entity & elem = mesh.declare_entity(entity_rank, p_rank+1 /*elem_id*/, empty_parts);
297 
298  // Create node
299  Entity & node = mesh.declare_entity(NODE_RANK, p_rank+1 /*node_id*/, empty_parts);
300 
301  // Add degenerate relations
302  const unsigned nodes_per_elem = 4;
303  for (unsigned i = 0; i < nodes_per_elem; ++i) {
304  mesh.declare_relation( elem, node, i );
305  }
306 
307  // Elem should have nodes-per-elem relations
308  STKUNIT_ASSERT_EQUAL( nodes_per_elem, elem.relations().size() );
309 
310  // Destroy relation one-by-one, always checking that appropriate number
311  // of relations remain.
312  for (unsigned i = 0; i < nodes_per_elem; ++i) {
313  mesh.destroy_relation( elem, node, i );
314  STKUNIT_ASSERT_EQUAL( nodes_per_elem - (i+1), elem.relations().size() );
315  }
316 
317  mesh.modification_end();
318 }
319 
320 STKUNIT_UNIT_TEST(UnitTestingOfRelation, testRelationAttribute)
321 {
322  (void)test_info_;
323  // Test relation attribute
324 
325  stk_classic::ParallelMachine pm = MPI_COMM_WORLD;
326 
327  // Set up meta and bulk data
328  const unsigned spatial_dim = 2;
329  FEMMetaData meta_data(spatial_dim);
330  meta_data.commit();
331  BulkData mesh(FEMMetaData::get_meta_data(meta_data), pm);
332  unsigned p_rank = mesh.parallel_rank();
333 
334  // Begin modification cycle so we can create the entities and relations
335  mesh.modification_begin();
336 
337  // We're just going to add everything to the universal part
338  stk_classic::mesh::PartVector empty_parts;
339 
340  // Create element
341  const EntityRank entity_rank = meta_data.element_rank();
342  Entity & elem = mesh.declare_entity(entity_rank, p_rank+1 /*elem_id*/, empty_parts);
343 
344  // Create node
345  Entity & node = mesh.declare_entity(NODE_RANK, p_rank+1 /*node_id*/, empty_parts);
346 
347  mesh.declare_relation( elem, node, 0 );
348 
349  const Relation & my_relation = *(elem.relations(NODE_RANK).begin());
350  my_relation.set_attribute(6u);
351 
352  STKUNIT_ASSERT_EQUAL( my_relation.attribute(), 6u);
353 
354  mesh.modification_end();
355 }
356 
357 STKUNIT_UNIT_TEST(UnitTestingOfRelation, testDoubleDeclareOfRelation)
358 {
359  (void)test_info_;
360  // It should be legal to declare the same relation between shared
361  // entities on two procs.
362  //
363  // 1---3---5
364  // | 1 | 2 |
365  // 2---4---6
366  //
367  // To test this, we use the mesh above, with elem 1 going on rank 0 and
368  // elem 2 going on rank 1. Nodes 3,4 are shared along with the edge between
369  // nodes 3 and 4. On both procs we declare relations from the shared edge
370  // to the shared nodes on both procs.
371  //
372  // TODO: If we change how declare_relation works, not requiring all
373  // sharers to declare the same relations, but instead allowing just
374  // the owner to declare relations, that should be tested here.
375 
376  stk_classic::ParallelMachine pm = MPI_COMM_WORLD;
377  MPI_Barrier( MPI_COMM_WORLD );
378 
379  // Set up meta and bulk data
380  const unsigned spatial_dim = 2;
381  FEMMetaData meta_data(spatial_dim);
382  meta_data.commit();
383  BulkData mesh(FEMMetaData::get_meta_data(meta_data), pm);
384  unsigned p_rank = mesh.parallel_rank();
385  unsigned p_size = mesh.parallel_size();
386 
387  // Bail if we only have one proc
388  if (p_size == 1) {
389  return;
390  }
391 
392  // Begin modification cycle so we can create the entities and relations
393  mesh.modification_begin();
394 
395  Entity* elem_ptr = NULL;
396  Entity* edge_ptr = NULL;
397  EntityVector nodes;
398  const unsigned nodes_per_elem = 4, nodes_per_side = 2;
399 
400  if (p_rank < 2) {
401  // We're just going to add everything to the universal part
402  stk_classic::mesh::PartVector empty_parts;
403 
404  // Create element
405  const EntityRank entity_rank = meta_data.element_rank();
406  Entity & elem = mesh.declare_entity(entity_rank, p_rank+1 /*elem_id*/, empty_parts);
407  elem_ptr = &elem;
408 
409  // Create nodes
410  const unsigned starting_node_id = p_rank * nodes_per_side + 1;
411  for (unsigned id = starting_node_id; id < starting_node_id + nodes_per_elem; ++id) {
412  nodes.push_back(&mesh.declare_entity(NODE_RANK, id, empty_parts));
413  }
414 
415  // Add relations to nodes
416  unsigned rel_id = 0;
417  for (EntityVector::iterator itr = nodes.begin(); itr != nodes.end(); ++itr, ++rel_id) {
418  mesh.declare_relation( elem, **itr, rel_id );
419  }
420 
421  // Create edge
422  const EntityRank edge_rank = meta_data.side_rank();
423  Entity & edge = mesh.declare_entity(edge_rank, 1 /*id*/, empty_parts);
424  edge_ptr = &edge;
425 
426  // Set up relation from elem to edge
427  mesh.declare_relation( *elem_ptr, *edge_ptr, 0 /*rel-id*/ );
428  }
429 
430  mesh.modification_end();
431 
432  mesh.modification_begin();
433 
434  if (p_rank < 2) {
435  // Set up relations from edge to nodes
436  unsigned rel_id = 0;
437  const unsigned starting_node_idx = (1 - p_rank) * nodes_per_side;
438  for (unsigned node_idx = starting_node_idx;
439  node_idx < starting_node_idx + nodes_per_side;
440  ++node_idx, ++rel_id) {
441  mesh.declare_relation( *edge_ptr, *nodes[node_idx], rel_id );
442  }
443  }
444 
445  mesh.modification_end();
446 }
447 
448 }
Part & locally_owned_part() const
Subset for the problem domain that is owned by the local process. Ghost entities are not members of t...
void declare_relation(Entity &e_from, Entity &e_to, const RelationIdentifier local_id)
Declare a relation and its converse between entities in the same mesh.
FEMMetaData is a class that implements a Finite Element Method skin on top of the Sierra Tool Kit Met...
Definition: FEMMetaData.hpp:54
Ghosting & create_ghosting(const std::string &name)
Asymmetric parallel relations for owner-to-ghosted mesh entities.
Data for ghosting mesh entities.
Definition: Ghosting.hpp:28
EntityRank element_rank() const
Returns the element rank which is always equal to spatial dimension.
Part & universal_part() const
Universal subset for the problem domain. All other parts are a subset of the universal part...
This is a class for selecting buckets based on a set of meshparts and set logic.
Definition: Selector.hpp:112
const std::vector< Bucket * > & buckets(EntityRank rank) const
Query all buckets of a given entity rank.
Definition: BulkData.hpp:195
field_type & put_field(field_type &field, EntityRank entity_rank, const Part &part, const void *init_value=NULL)
Declare a field to exist for a given entity type and Part.
An application-defined subset of a problem domain.
Definition: Part.hpp:49
unsigned parallel_machine_rank(ParallelMachine parallel_machine)
Member function parallel_machine_rank ...
Definition: Parallel.cpp:29
void destroy_all_ghosting()
Empty every single Ghosting. Same result, but more efficient than, calling change_ghosting to remove ...
bool modification_end()
Parallel synchronization of modifications and transition to the guaranteed parallel consistent state...
bool modification_begin()
Begin a modification phase during which the mesh bulk data could become parallel inconsistent. This is a parallel synchronous call. The first time this method is called the mesh meta data is verified to be committed and parallel consistent. An exception is thrown if this verification fails.
Definition: BulkData.cpp:172
PairIterRelation relations() const
All Entity relations for which this entity is a member. The relations are ordered from lowest entity-...
Definition: Entity.hpp:161
void get_entities(const BulkData &mesh, EntityRank entity_rank, std::vector< Entity *> &entities)
Get all entities of the specified type, sorted by ID.
Definition: GetEntities.cpp:25
A relation between two mesh entities with a relation identifier and kind .
Definition: Relation.hpp:58
unsigned parallel_machine_size(ParallelMachine parallel_machine)
Member function parallel_machine_size ...
Definition: Parallel.cpp:18
Manager for an integrated collection of entities, entity relations, and buckets of field data...
Definition: BulkData.hpp:49
void commit()
Commit the part and field declarations so that the meta data manager can be used to create mesh bulk ...
field_type & declare_field(const std::string &name, unsigned number_of_states=1)
Declare a field of the given field_type, test name, and number of states.
A fundamental unit within the discretization of a problem domain, including but not limited to nodes...
Definition: Entity.hpp:120
MPI_Comm ParallelMachine
Definition: Parallel.hpp:32
unsigned parallel_rank() const
Rank of the parallel machine&#39;s local processor.
Definition: BulkData.hpp:85
Entity & declare_entity(EntityRank ent_rank, EntityId ent_id, const PartVector &parts)
Create or retrieve a locally owned entity of a given rank and id.
Definition: BulkData.cpp:215
std::vector< Part *> PartVector
Collections of parts are frequently maintained as a vector of Part pointers.
Definition: Types.hpp:31
EntityRank entity_rank(const EntityKey &key)
Given an entity key, return an entity type (rank).