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 }
stk_classic::mesh::put_field
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.
stk_classic::mesh::fixtures::RingFixture
Definition: RingFixture.hpp:37
stk_classic::mesh::Relation
A relation between two mesh entities with a relation identifier and kind .
Definition: Relation.hpp:58
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::parallel_rank
unsigned parallel_rank() const
Rank of the parallel machine's local processor.
Definition: BulkData.hpp:85
stk_classic::mesh::fixtures::BoxFixture
Definition: BoxFixture.hpp:26
stk_classic::mesh::Field< double >
stk_classic::mesh::Part
An application-defined subset of a problem domain.
Definition: Part.hpp:49
stk_classic::mesh::BulkData::declare_entity
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
stk_classic::mesh::fem::FEMMetaData::locally_owned_part
Part & locally_owned_part() const
Subset for the problem domain that is owned by the local process. Ghost entities are not members of t...
Definition: FEMMetaData.hpp:277
stk_classic::ParallelMachine
MPI_Comm ParallelMachine
Definition: Parallel.hpp:32
stk_classic::mesh::BulkData::destroy_all_ghosting
void destroy_all_ghosting()
Empty every single Ghosting. Same result, but more efficient than, calling change_ghosting to remove ...
Definition: BulkDataGhosting.cpp:102
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::mesh::get_entities
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
stk_classic::mesh::BulkData::declare_relation
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.
Definition: BulkDataRelation.cpp:129
stk_classic::mesh::fem::FEMMetaData::commit
void commit()
Commit the part and field declarations so that the meta data manager can be used to create mesh bulk ...
Definition: FEMMetaData.hpp:466
stk_classic::mesh::BulkData::create_ghosting
Ghosting & create_ghosting(const std::string &name)
Asymmetric parallel relations for owner-to-ghosted mesh entities.
Definition: BulkDataGhosting.cpp:38
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::Entity::relations
PairIterRelation relations() const
All Entity relations for which this entity is a member. The relations are ordered from lowest entity-...
Definition: Entity.hpp:161
stk_classic::mesh::PartVector
std::vector< Part * > PartVector
Collections of parts are frequently maintained as a vector of Part pointers.
Definition: Types.hpp:31
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::entity_rank
EntityRank entity_rank(const EntityKey &key)
Given an entity key, return an entity type (rank).
Definition: base/EntityKey.hpp:161
stk_classic::mesh::fem::FEMMetaData::declare_field
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.
Definition: FEMMetaData.hpp:427
stk_classic::parallel_machine_rank
unsigned parallel_machine_rank(ParallelMachine parallel_machine)
Member function parallel_machine_rank ...
Definition: Parallel.cpp:29
stk_classic::mesh::fem::FEMMetaData::element_rank
EntityRank element_rank() const
Returns the element rank which is always equal to spatial dimension.
Definition: FEMMetaData.hpp:160
stk_classic::mesh::fem::FEMMetaData
FEMMetaData is a class that implements a Finite Element Method skin on top of the Sierra Tool Kit Met...
Definition: FEMMetaData.hpp:54
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::fem::FEMMetaData::universal_part
Part & universal_part() const
Universal subset for the problem domain. All other parts are a subset of the universal part.
Definition: FEMMetaData.hpp:272
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