Sierra Toolkit  Version of the Day
UnitTestSkinning.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 <stk_util/unit_test_support/stk_utest_macros.hpp>
10 
11 #include <stk_util/parallel/Parallel.hpp>
12 
13 #include <stk_mesh/base/MetaData.hpp>
14 #include <stk_mesh/base/BulkData.hpp>
15 #include <stk_mesh/base/Entity.hpp>
16 #include <stk_mesh/base/GetEntities.hpp>
17 #include <stk_mesh/base/Selector.hpp>
18 #include <stk_mesh/base/GetBuckets.hpp>
19 #include <stk_mesh/base/Comm.hpp>
20 
21 #include <stk_mesh/fem/BoundaryAnalysis.hpp>
22 #include <stk_mesh/fem/SkinMesh.hpp>
23 #include <stk_mesh/fem/FEMHelpers.hpp>
24 
25 #include <stk_mesh/fixtures/GridFixture.hpp>
26 
27 #include <stk_util/parallel/ParallelReduce.hpp>
28 
29 #include <Shards_BasicTopologies.hpp>
30 
31 #include <iomanip>
32 #include <algorithm>
33 
34 static const size_t NODE_RANK = stk_classic::mesh::fem::FEMMetaData::NODE_RANK;
35 
36 class UnitTestStkMeshSkinning {
37 public:
38  UnitTestStkMeshSkinning(stk_classic::ParallelMachine pm) : m_comm(pm), m_num_procs(0), m_rank(0)
39  {
40  m_num_procs = stk_classic::parallel_machine_size( m_comm );
41  m_rank = stk_classic::parallel_machine_rank( m_comm );
42  }
43 
44  void test_skinning();
45 
47  int m_num_procs;
48  int m_rank;
49 };
50 
51 namespace {
52 
53 STKUNIT_UNIT_TEST( UnitTestStkMeshSkinning , testUnit )
54 {
55  UnitTestStkMeshSkinning unit(MPI_COMM_WORLD);
56  unit.test_skinning();
57 }
58 
59 STKUNIT_UNIT_TEST( UnitTestStkMeshSkinning , testSingleShell )
60 {
61  const int spatial_dimension = 3;
63  fem_meta.FEM_initialize(spatial_dimension, stk_classic::mesh::fem::entity_rank_names(spatial_dimension));
65  stk_classic::mesh::BulkData bulk_data( meta_data, MPI_COMM_WORLD );
66  const stk_classic::mesh::EntityRank element_rank = fem_meta.element_rank();
67 
68  const unsigned p_rank = bulk_data.parallel_rank();
69 
70  stk_classic::mesh::Part & skin_part = fem_meta.declare_part("skin_part");
71 
72  stk_classic::mesh::fem::CellTopology shell_top(shards::getCellTopologyData<shards::ShellQuadrilateral<4> >());
73  stk_classic::mesh::Part & shell_part = fem_meta.declare_part("shell_part", shell_top);
74 
75  fem_meta.commit();
76 
77  bulk_data.modification_begin();
78 
79  if ( p_rank == 0 ) {
80 
81  stk_classic::mesh::EntityId elem_node[4] ;
82 
83  // Query nodes from this simple grid fixture via the (i,j,k) indices.
84  elem_node[0] = 1;
85  elem_node[1] = 2;
86  elem_node[2] = 3;
87  elem_node[3] = 4;
88 
89  stk_classic::mesh::EntityId elem_id = 1;
90 
91  stk_classic::mesh::fem::declare_element( bulk_data, shell_part, elem_id, elem_node);
92 
93  }
94  bulk_data.modification_end();
95 
96 
97  stk_classic::mesh::skin_mesh( bulk_data, element_rank, &skin_part);
98 
99  {
100  const unsigned mesh_rank = element_rank;
101  const stk_classic::mesh::MetaData & meta = stk_classic::mesh::MetaData::get(bulk_data);
102  stk_classic::mesh::Selector select_skin = skin_part & meta.locally_owned_part() ;
103  const std::vector<stk_classic::mesh::Bucket*>& buckets = bulk_data.buckets( mesh_rank -1);
104  int num_skin_entities = stk_classic::mesh::count_selected_entities( select_skin, buckets);
105 
106 
107  stk_classic::all_reduce(MPI_COMM_WORLD, stk_classic::ReduceSum<1>(&num_skin_entities));
108 
109  // Verify that the correct 6 sides are present.
110 
111  STKUNIT_ASSERT_EQUAL( num_skin_entities, 2 );
112  }
113 }
114 
115 } //end namespace
116 
117 void UnitTestStkMeshSkinning::test_skinning()
118 {
119  // This test will only work for np=1
120  if (m_num_procs > 1) {
121  return;
122  }
123 
124  stk_classic::mesh::fixtures::GridFixture grid_mesh(MPI_COMM_WORLD);
125 
126  stk_classic::mesh::BulkData& bulk_data = grid_mesh.bulk_data();
127  stk_classic::mesh::fem::FEMMetaData& fem_meta = grid_mesh.fem_meta();
128  const stk_classic::mesh::EntityRank element_rank = fem_meta.element_rank();
129 
130  // Create a part for the skin and the shells
131  stk_classic::mesh::Part & skin_part = fem_meta.declare_part("skin_part");
132  stk_classic::mesh::fem::CellTopology line_top(shards::getCellTopologyData<shards::ShellLine<2> >());
133  stk_classic::mesh::Part & shell_part = fem_meta.declare_part("shell_part", line_top);
134  fem_meta.commit();
135 
136  // Begin modification cycle
137  grid_mesh.bulk_data().modification_begin();
138 
139  // Generate the plain grid
140  grid_mesh.generate_grid();
141 
142  // Add the shells
143  std::vector<unsigned> count;
144  stk_classic::mesh::Selector locally_owned(fem_meta.locally_owned_part());
145  stk_classic::mesh::count_entities(locally_owned, bulk_data, count);
146  const unsigned num_shell_1_faces = 4;
147  const unsigned num_shell_2_faces = 2;
148  const unsigned num_shell_faces = num_shell_1_faces + num_shell_2_faces;
149  const unsigned num_entities = count[NODE_RANK] +
150  count[element_rank];
151 
152  stk_classic::mesh::PartVector shell_parts;
153  shell_parts.push_back(&shell_part);
154 
155  std::vector<stk_classic::mesh::Entity*> shell_faces;
156  for (unsigned i = 1; i <= num_shell_faces; ++i) {
157  stk_classic::mesh::Entity& new_shell = bulk_data.declare_entity(element_rank,
158  num_entities + i,
159  shell_parts);
160  shell_faces.push_back(&new_shell);
161  }
162 
163  // Set up relationships for shells
164 
165  // declare shell relationships for first shell
166  unsigned node_list_1[5] = {21, 26, 31, 36, 41};
167  for (unsigned i = 0; i < num_shell_1_faces; ++i) {
168  stk_classic::mesh::Entity& shell = *(shell_faces[i]);
169  stk_classic::mesh::Entity& node1 = *(bulk_data.get_entity(NODE_RANK, node_list_1[i]));
170  stk_classic::mesh::Entity& node2 = *(bulk_data.get_entity(NODE_RANK, node_list_1[i+1]));
171  bulk_data.declare_relation(shell, node1, 0);
172  bulk_data.declare_relation(shell, node2, 1);
173  }
174 
175  // declare shell relationships for second shell
176  unsigned node_list_2[3] = {31, 36, 41};
177  for (unsigned i = 0; i < num_shell_2_faces; ++i) {
178  stk_classic::mesh::Entity& shell = *(shell_faces[i + num_shell_1_faces]);
179  stk_classic::mesh::Entity& node1 = *(bulk_data.get_entity(NODE_RANK, node_list_2[i]));
180  stk_classic::mesh::Entity& node2 = *(bulk_data.get_entity(NODE_RANK, node_list_2[i+1]));
181  bulk_data.declare_relation(shell, node1, 0);
182  bulk_data.declare_relation(shell, node2, 1);
183  }
184 
185  grid_mesh.bulk_data().modification_end();
186 
187  // skin the boundary
188  stk_classic::mesh::skin_mesh(bulk_data, element_rank, &skin_part);
189 
190  // Grab the skin entities
191  stk_classic::mesh::Selector skin_selector(skin_part);
192  const std::vector<stk_classic::mesh::Bucket*>& edge_buckets = bulk_data.buckets(fem_meta.edge_rank());
193  std::vector<stk_classic::mesh::Entity*> skin_entities;
194  stk_classic::mesh::get_selected_entities(skin_selector, edge_buckets, skin_entities);
195 
196  unsigned num_expected_skin_entites = 16;
197  STKUNIT_EXPECT_EQUAL(num_expected_skin_entites, skin_entities.size());
198 
199  // Map the element id to the number of skins associated with that element
200 
201  std::map<unsigned, unsigned> results;
202  std::map<unsigned, unsigned> expected_results;
203 
204  expected_results[1] = 2;
205  expected_results[2] = 1;
206  expected_results[3] = 1;
207  expected_results[4] = 1;
208  expected_results[5] = 1;
209  expected_results[9] = 1;
210  expected_results[13] = 2;
211  expected_results[14] = 1;
212  expected_results[15] = 1;
213  expected_results[16] = 1;
214  expected_results[42] = 1;
215  expected_results[43] = 1;
216  expected_results[44] = 1;
217  expected_results[45] = 1;
218  expected_results[46] = 1;
219  expected_results[47] = 1;
220 
221  // Vector of of vector of entities (shells) that are expected to share a skin
222 
223  std::set<std::set<unsigned> > sharing;
224  std::set<std::set<unsigned> > expected_sharing;
225 
226  std::set<unsigned> temp;
227  temp.insert(44);
228  temp.insert(46);
229  expected_sharing.insert(temp);
230 
231  temp.clear();
232  temp.insert(45);
233  temp.insert(47);
234  expected_sharing.insert(temp);
235 
236  // map skin-id to ids of elements it is attached to; we will use this to
237  // compute sharing
238  for (std::vector<stk_classic::mesh::Entity*>::const_iterator
239  itr = skin_entities.begin(); itr != skin_entities.end(); ++itr) {
240  stk_classic::mesh::PairIterRelation upward_relation_itr =
241  (*itr)->relations(element_rank);
242  bool has_multiple = upward_relation_itr.size() > 1;
243  std::set<unsigned> sharing_elements;
244  for ( ; !upward_relation_itr.empty() ; ++upward_relation_itr ) {
245  unsigned elem_id = upward_relation_itr->entity()->identifier();
246  if (results.find(elem_id) != results.end()) {
247  ++results[elem_id];
248  }
249  else {
250  results[elem_id] = 1;
251  }
252 
253  if (has_multiple) {
254  sharing_elements.insert(elem_id);
255  }
256  }
257  if (has_multiple) {
258  sharing.insert(sharing_elements);
259  }
260  }
261 
262  STKUNIT_EXPECT_TRUE(results == expected_results);
263  STKUNIT_EXPECT_TRUE(sharing == expected_sharing);
264 }
265 
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
The manager of an integrated collection of parts and fields.
Definition: MetaData.hpp:56
unsigned count_selected_entities(const Selector &selector, const std::vector< Bucket * > &input_buckets)
Count entities in selected buckets (selected by the given selector instance), and sorted by ID...
Definition: GetEntities.cpp:59
Entity & declare_element(BulkData &mesh, Part &part, const EntityId elem_id, const EntityId node_id[])
Declare an element member of a Part with a CellTopology and nodes conformal to that topology...
Definition: FEMHelpers.cpp:72
EntityRank element_rank() const
Returns the element rank which is always equal to spatial dimension.
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
Entity * get_entity(EntityRank entity_rank, EntityId entity_id) const
Get entity with a given key.
Definition: BulkData.hpp:211
An application-defined subset of a problem domain.
Definition: Part.hpp:49
void get_selected_entities(const Selector &selector, const std::vector< Bucket * > &input_buckets, std::vector< Entity * > &entities)
Get entities in selected buckets (selected by the given selector instance), and sorted by ID...
Definition: GetEntities.cpp:77
unsigned parallel_machine_rank(ParallelMachine parallel_machine)
Member function parallel_machine_rank ...
Definition: Parallel.cpp:29
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: MetaData.hpp:93
Part & declare_part(const std::string &name, fem::CellTopology cell_topology)
Declare a part with a given cell topology.
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
static MetaData & get_meta_data(FEMMetaData &fem_meta)
Getter for MetaData off of a FEMMetaData object.
void commit()
Commit the part and field declarations so that the meta data manager can be used to create mesh bulk ...
A fundamental unit within the discretization of a problem domain, including but not limited to nodes...
Definition: Entity.hpp:120
void count_entities(const Selector &selector, const BulkData &mesh, std::vector< EntityRank > &count)
Local count selected entities of each type.
EntityRank edge_rank() const
Returns the edge rank which changes depending on spatial dimension.
MPI_Comm ParallelMachine
Definition: Parallel.hpp:32
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
void all_reduce(ParallelMachine, const ReduceOp &)
eastl::iterator_traits< InputIterator >::difference_type count(InputIterator first, InputIterator last, const T &value)
void FEM_initialize(size_t spatial_dimension, const std::vector< std::string > &in_entity_rank_names=std::vector< std::string >())
Initialize the spatial dimension and an optional list of entity rank names associated with each rank...
Definition: FEMMetaData.cpp:61