Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_STK_SurfaceNodeNormals.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Panzer: A partial differential equation assembly
4 // engine for strongly coupled complex multiphysics systems
5 //
6 // Copyright 2011 NTESS and the Panzer contributors.
7 // SPDX-License-Identifier: BSD-3-Clause
8 // *****************************************************************************
9 // @HEADER
10 
12 
13 #include "Panzer_STK_Interface.hpp"
17 #include "Panzer_Workset_Builder.hpp"
20 #include "Panzer_CellData.hpp"
22 
23 #include <stk_mesh/base/Selector.hpp>
24 #include <stk_mesh/base/GetEntities.hpp>
25 #include <stk_mesh/base/GetBuckets.hpp>
26 #include <stk_mesh/base/CreateAdjacentEntities.hpp>
27 
28 #include "Shards_CellTopology.hpp"
29 //#include "Intrepid2_FunctionSpaceTools.hpp"
30 #include "Intrepid2_CellTools_Serial.hpp"
31 #include "Teuchos_Assert.hpp"
32 
33 namespace panzer_stk {
34 
35  void computeSidesetNodeNormals(std::unordered_map<unsigned,std::vector<double> >& normals,
37  const std::string& sidesetName,
38  const std::string& elementBlockName,
39  std::ostream* /* out */,
40  std::ostream* pout)
41  {
42  using panzer::Cell;
43  using panzer::NODE;
44  using panzer::Dim;
45 
46  using Teuchos::RCP;
47 
48  panzer::MDFieldArrayFactory af("",true);
49 
50  RCP<stk::mesh::MetaData> metaData = mesh->getMetaData();
51  RCP<stk::mesh::BulkData> bulkData = mesh->getBulkData();
52 
53  // Grab all nodes for a surface including ghosted to get correct contributions to normal average
54  stk::mesh::Part * sidePart = mesh->getSideset(sidesetName);
55  stk::mesh::Part * elmtPart = mesh->getElementBlockPart(elementBlockName);
56  stk::mesh::Selector sideSelector = *sidePart;
57  stk::mesh::Selector blockSelector = *elmtPart;
58  stk::mesh::Selector mySelector = metaData->universal_part() & blockSelector & sideSelector;
59  std::vector<stk::mesh::Entity> sides;
60  stk::mesh::get_selected_entities(mySelector,bulkData->buckets(metaData->side_rank()),sides);
61 
62  std::vector<std::size_t> missingElementIndices;
63  std::vector<std::size_t> localSideTopoIDs;
64  std::vector<stk::mesh::Entity> parentElements;
65  panzer_stk::workset_utils::getUniversalSubcellElements(*mesh,elementBlockName,sides,localSideTopoIDs,parentElements,missingElementIndices);
66 
67  // Delete all sides whose neighboring element in elementBlockName is not in the current process
68  std::vector<std::size_t>::reverse_iterator index;
69  for(index=missingElementIndices.rbegin(); index != missingElementIndices.rend(); ++index) {
70  sides.erase(sides.begin()+*index);
71  }
72 
73  if (pout != NULL) {
74  for (std::size_t i=0; i < localSideTopoIDs.size(); ++i) {
75  *pout << "parent element: "
76  << " gid(" << bulkData->identifier(parentElements[i]) << ")"
77  << ", local_face(" << localSideTopoIDs[i] << ")"
78  << std::endl;
79  }
80  }
81 
82  // Do a single element at a time so that we don't have to batch up
83  // into faces
84 
85  // maps a panzer local element id to a list of normals
86  std::unordered_map<unsigned,std::vector<double> > nodeNormals;
87 
88  TEUCHOS_ASSERT(sides.size() == localSideTopoIDs.size());
89  TEUCHOS_ASSERT(localSideTopoIDs.size() == parentElements.size());
90 
91  RCP<const shards::CellTopology> parentTopology = mesh->getCellTopology(elementBlockName);
92  //Intrepid2::DefaultCubatureFactory cubFactory;
93  int cubDegree = 1;
94 
95  std::vector<stk::mesh::Entity>::const_iterator side = sides.begin();
96  std::vector<std::size_t>::const_iterator sideID = localSideTopoIDs.begin();
97  std::vector<stk::mesh::Entity>::const_iterator parentElement = parentElements.begin();
98 
99  // KK: invoke serial interface; cubDegree is 1 and integration point is one
100  // for debugging statement, use max dimension
101  auto side_parametrization = Intrepid2::RefSubcellParametrization<Kokkos::HostSpace>::get(2,parentTopology->getKey());
102  Kokkos::DynRankView<double,Kokkos::HostSpace> normal_at_point("normal",3); // parentTopology->getDimension());
103  for ( ; sideID != localSideTopoIDs.end(); ++side,++sideID,++parentElement) {
104 
105  std::vector<stk::mesh::Entity> elementEntities;
106  elementEntities.push_back(*parentElement); // notice this is size 1!
108  = af.buildStaticArray<double,Cell,NODE,Dim>("",elementEntities.size(), parentTopology->getNodeCount(), mesh->getDimension());
109  auto node_view = nodes.get_view();
110  mesh->getElementNodesNoResize(elementEntities,elementBlockName,node_view);
111 
112  panzer::CellData sideCellData(1,*sideID,parentTopology); // this is size 1 because elementEntties is size 1!
113  RCP<panzer::IntegrationRule> ir = Teuchos::rcp(new panzer::IntegrationRule(cubDegree,sideCellData));
114 
116  iv.setupArrays(ir);
117  iv.evaluateValues(nodes);
118 
119  // KK: use serial interface; jac_at_point (D,D) from (C,P,D,D)
120  {
121  auto jac_at_point = Kokkos::subview(iv.jac.get_view(), 0, 0, Kokkos::ALL(), Kokkos::ALL());
122  auto jac_at_point_h = Kokkos::create_mirror_view(jac_at_point);
123  Kokkos::deep_copy(jac_at_point_h, jac_at_point);
124  Intrepid2::Impl::
125  CellTools::Serial::getPhysicalSideNormal(normal_at_point, side_parametrization, jac_at_point_h, *sideID);
126  }
127 
128  if (pout != NULL) {
129  *pout << "element normals: "
130  << "gid(" << bulkData->identifier(*parentElement) << ")"
131  << ", normal(" << normal_at_point(0) << "," << normal_at_point(1) << "," << normal_at_point(2) << ")"
132  << std::endl;
133  }
134 
135  // loop over nodes in nodes in side and add normal contribution for averaging
136  const size_t numNodes = bulkData->num_nodes(*side);
137  stk::mesh::Entity const* nodeRelations = bulkData->begin_nodes(*side);
138  for (size_t n=0; n<numNodes; ++n) {
139  stk::mesh::Entity node = nodeRelations[n];
140  for (unsigned dim = 0; dim < parentTopology->getDimension(); ++dim) {
141  nodeNormals[bulkData->identifier(node)].push_back(normal_at_point(dim));
142  }
143  }
144 
145  }
146 
147  // Now do the averaging of contributions
148  //std::unordered_map<unsigned,std::vector<double> > normals;
149  for (std::unordered_map<unsigned,std::vector<double> >::const_iterator node = nodeNormals.begin(); node != nodeNormals.end(); ++node) {
150 
151  TEUCHOS_ASSERT( (node->second.size() % parentTopology->getDimension()) == 0);
152 
153  int numSurfaceContributions = node->second.size() / parentTopology->getDimension();
154  std::vector<double> contribArea(numSurfaceContributions);
155  double totalArea = 0.0;
156  for (int surface = 0; surface < numSurfaceContributions; ++surface) {
157 
158  double sum = 0.0;
159  for (unsigned dim = 0; dim < parentTopology->getDimension(); ++dim)
160  sum += (node->second[surface*parentTopology->getDimension() + dim]) *
161  (node->second[surface*parentTopology->getDimension() + dim]);
162 
163  contribArea[surface] = std::sqrt(sum);
164 
165  totalArea += contribArea[surface];
166  }
167 
168  // change the contribArea to the scale factor for each contribution
169  for (std::size_t i = 0; i < contribArea.size(); ++i)
170  contribArea[i] /= totalArea;
171 
172  // loop over contributions and compute final normal values
173  normals[node->first].resize(parentTopology->getDimension());
174  for (unsigned dim = 0; dim < parentTopology->getDimension(); ++dim) {
175  normals[node->first][dim] = 0.0;
176  for (int surface = 0; surface < numSurfaceContributions; ++surface) {
177  normals[node->first][dim] += node->second[surface*parentTopology->getDimension() + dim] * contribArea[surface] / totalArea;
178  }
179  }
180 
181  if (pout != NULL) {
182  *pout << "surface normal before normalization: "
183  << "gid(" << node->first << ")"
184  << ", normal(" << normals[node->first][0] << "," << normals[node->first][1] << "," << normals[node->first][2] << ")"
185  << std::endl;
186  }
187 
188  double sum = 0.0;
189  for (unsigned dim = 0; dim < parentTopology->getDimension(); ++dim)
190  sum += normals[node->first][dim] * normals[node->first][dim];
191 
192  for (unsigned dim = 0; dim < parentTopology->getDimension(); ++dim)
193  normals[node->first][dim] /= std::sqrt(sum);
194 
195  if (pout != NULL) {
196  *pout << "surface normal after normalization: "
197  << "gid(" << node->first << ")"
198  << ", normal("
199  << normals[node->first][0] << ","
200  << normals[node->first][1] << ","
201  << normals[node->first][2] << ")"
202  << std::endl;
203  }
204 
205  }
206 
207  }
208 
209  void computeSidesetNodeNormals(std::unordered_map<std::size_t,Kokkos::DynRankView<double,PHX::Device> >& normals,
211  const std::string& sidesetName,
212  const std::string& elementBlockName,
213  std::ostream* out,
214  std::ostream* pout)
215  {
216  using Teuchos::RCP;
217 
218  std::unordered_map<unsigned,std::vector<double> > nodeEntityIdToNormals;
219 
220  computeSidesetNodeNormals(nodeEntityIdToNormals,mesh,sidesetName,elementBlockName,out,pout);
221 
222  RCP<stk::mesh::MetaData> metaData = mesh->getMetaData();
223  RCP<stk::mesh::BulkData> bulkData = mesh->getBulkData();
224 
225  // Grab all nodes for a surface including ghosted to get correct contributions to normal average
226  stk::mesh::Part * sidePart = mesh->getSideset(sidesetName);
227  stk::mesh::Part * elmtPart = mesh->getElementBlockPart(elementBlockName);
228  stk::mesh::Selector sideSelector = *sidePart;
229  stk::mesh::Selector blockSelector = *elmtPart;
230  stk::mesh::Selector mySelector = metaData->universal_part() & blockSelector & sideSelector;
231  std::vector<stk::mesh::Entity> sides;
232  stk::mesh::get_selected_entities(mySelector,bulkData->buckets(metaData->side_rank()),sides);
233 
234  RCP<const shards::CellTopology> parentTopology = mesh->getCellTopology(elementBlockName);
235 
236  std::vector<std::size_t> missingElementIndices;
237  std::vector<std::size_t> localSideTopoIDs;
238  std::vector<stk::mesh::Entity> parentElements;
239  panzer_stk::workset_utils::getUniversalSubcellElements(*mesh,elementBlockName,sides,localSideTopoIDs,parentElements,missingElementIndices);
240 
241  // Delete all sides whose neighboring element in elementBlockName is not in the current process
242  std::vector<std::size_t>::reverse_iterator index;
243  for(index=missingElementIndices.rbegin(); index != missingElementIndices.rend(); ++index) {
244  sides.erase(sides.begin()+*index);
245  }
246 
247  std::vector<stk::mesh::Entity>::const_iterator side = sides.begin();
248  std::vector<std::size_t>::const_iterator sideID = localSideTopoIDs.begin();
249  std::vector<stk::mesh::Entity>::const_iterator parentElement = parentElements.begin();
250  for ( ; sideID != localSideTopoIDs.end(); ++side,++sideID,++parentElement) {
251 
252  // loop over nodes in nodes in side element
253  const size_t numNodes = bulkData->num_nodes(*parentElement);
254  stk::mesh::Entity const* nodeRelations = bulkData->begin_nodes(*parentElement);
255 
256  normals[mesh->elementLocalId(*parentElement)] = Kokkos::DynRankView<double,PHX::Device>("normals",numNodes,parentTopology->getDimension());
257  auto normals_h = Kokkos::create_mirror_view(normals[mesh->elementLocalId(*parentElement)]);
258  for (size_t nodeIndex=0; nodeIndex<numNodes; ++nodeIndex) {
259  stk::mesh::Entity node = nodeRelations[nodeIndex];
260  // if the node is on the sideset, insert, otherwise set normal
261  // to zero (it is an interior node of the parent element).
262  if (nodeEntityIdToNormals.find(bulkData->identifier(node)) != nodeEntityIdToNormals.end()) {
263  for (unsigned dim = 0; dim < parentTopology->getDimension(); ++dim) {
264  normals_h(nodeIndex,dim) = (nodeEntityIdToNormals[bulkData->identifier(node)])[dim];
265  }
266  }
267  else {
268  for (unsigned dim = 0; dim < parentTopology->getDimension(); ++dim) {
269  normals_h(nodeIndex,dim) = 0.0;
270  }
271  }
272  }
273  Kokkos::deep_copy(normals[mesh->elementLocalId(*parentElement)], normals_h);
274  }
275 
276  }
277 
278 }
void computeSidesetNodeNormals(std::unordered_map< unsigned, std::vector< double > > &normals, const Teuchos::RCP< const panzer_stk::STK_Interface > &mesh, const std::string &sidesetName, const std::string &elementBlockName, std::ostream *, std::ostream *pout)
Computes the normals for all nodes associated with a sideset surface.
void getElementNodesNoResize(const std::vector< std::size_t > &localIds, ArrayT &nodes) const
stk::mesh::Part * getElementBlockPart(const std::string &name) const
get the block part
PHX::MDField< Scalar, T0 > buildStaticArray(const std::string &str, int d0) const
stk::mesh::Part * getSideset(const std::string &name) const
std::size_t elementLocalId(stk::mesh::Entity elmt) const
unsigned getDimension() const
get the dimension
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Data for determining cell topology and dimensionality.
void getUniversalSubcellElements(const panzer_stk::STK_Interface &mesh, const std::string &blockId, const std::vector< stk::mesh::Entity > &entities, std::vector< std::size_t > &localEntityIds, std::vector< stk::mesh::Entity > &elements, std::vector< std::size_t > &missingElementIndices)
Teuchos::RCP< stk::mesh::BulkData > getBulkData() const
void setupArrays(const Teuchos::RCP< const panzer::IntegrationRule > &ir)
Sizes/allocates memory for arrays.
Teuchos::RCP< stk::mesh::MetaData > getMetaData() const
#define TEUCHOS_ASSERT(assertion_test)
void evaluateValues(const PHX::MDField< Scalar, Cell, NODE, Dim > &cell_node_coordinates, const int num_cells=-1, const Teuchos::RCP< const SubcellConnectivity > &face_connectivity=Teuchos::null, const int num_virtual_cells=-1)
Evaluate basis values.
Teuchos::RCP< const shards::CellTopology > getCellTopology(const std::string &eBlock) const