Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_STKConnManager.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 <vector>
14 
15 // Teuchos includes
16 #include "Teuchos_RCP.hpp"
17 
18 #include "Kokkos_DynRankView.hpp"
19 
24 
25 #include "Teuchos_FancyOStream.hpp"
26 
27 namespace panzer_stk {
28 
29 using Teuchos::RCP;
30 using Teuchos::rcp;
31 
32 // Object describing how to sort a vector of elements using
33 // local ID as the key
34 class LocalIdCompare {
35 public:
36  LocalIdCompare(const RCP<const STK_Interface> & mesh) : mesh_(mesh) {}
37 
38  // Compares two stk mesh entities based on local ID
39  bool operator() (stk::mesh::Entity a,stk::mesh::Entity b)
40  { return mesh_->elementLocalId(a) < mesh_->elementLocalId(b);}
41 
42 private:
43  RCP<const STK_Interface> mesh_;
44 };
45 
47  : stkMeshDB_(stkMeshDB), ownedElementCount_(0)
48 {
49 }
50 
53 {
55 }
56 
58 {
59  elements_ = Teuchos::null;
60 
61  elementBlocks_.clear();
62  elmtLidToConn_.clear();
63  connSize_.clear();
64  elmtToAssociatedElmts_.clear();
65 }
66 
68 {
69  clearLocalElementMapping(); // forget the past
70 
71  // build element block information
73  elements_ = Teuchos::rcp(new std::vector<stk::mesh::Entity>);
74 
75  // defines ordering of blocks
76  std::vector<std::string> blockIds;
77  stkMeshDB_->getElementBlockNames(blockIds);
78 
79  std::size_t blockIndex=0;
80  for(std::vector<std::string>::const_iterator idItr=blockIds.begin();
81  idItr!=blockIds.end();++idItr,++blockIndex) {
82  std::string blockId = *idItr;
83 
84  // grab elements on this block
85  std::vector<stk::mesh::Entity> blockElmts;
86  stkMeshDB_->getMyElements(blockId,blockElmts);
87 
88  // concatenate them into element LID lookup table
89  elements_->insert(elements_->end(),blockElmts.begin(),blockElmts.end());
90 
91  // build block to LID map
92  elementBlocks_[blockId] = Teuchos::rcp(new std::vector<LocalOrdinal>);
93  for(std::size_t i=0;i<blockElmts.size();i++)
94  elementBlocks_[blockId]->push_back(stkMeshDB_->elementLocalId(blockElmts[i]));
95  }
96 
97  ownedElementCount_ = elements_->size();
98 
99  blockIndex=0;
100  for(std::vector<std::string>::const_iterator idItr=blockIds.begin();
101  idItr!=blockIds.end();++idItr,++blockIndex) {
102  std::string blockId = *idItr;
103 
104  // grab elements on this block
105  std::vector<stk::mesh::Entity> blockElmts;
106  stkMeshDB_->getNeighborElements(blockId,blockElmts);
107 
108  // concatenate them into element LID lookup table
109  elements_->insert(elements_->end(),blockElmts.begin(),blockElmts.end());
110 
111  // build block to LID map
112  neighborElementBlocks_[blockId] = Teuchos::rcp(new std::vector<LocalOrdinal>);
113  for(std::size_t i=0;i<blockElmts.size();i++)
114  neighborElementBlocks_[blockId]->push_back(stkMeshDB_->elementLocalId(blockElmts[i]));
115  }
116 
117  // this expensive operation gurantees ordering of local IDs
118  std::sort(elements_->begin(),elements_->end(),LocalIdCompare(stkMeshDB_));
119 
120  // allocate space for element LID to Connectivty map
121  // connectivity size
122  elmtLidToConn_.clear();
123  elmtLidToConn_.resize(elements_->size(),0);
124 
125  connSize_.clear();
126  connSize_.resize(elements_->size(),0);
127 }
128 
129 void
131  LocalOrdinal & nodeIdCnt, LocalOrdinal & edgeIdCnt,
132  LocalOrdinal & faceIdCnt, LocalOrdinal & cellIdCnt,
133  GlobalOrdinal & nodeOffset, GlobalOrdinal & edgeOffset,
134  GlobalOrdinal & faceOffset, GlobalOrdinal & cellOffset) const
135 {
136  // get the global counts for all the nodes, faces, edges and cells
137  GlobalOrdinal maxNodeId = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank());
138  GlobalOrdinal maxEdgeId = stkMeshDB_->getMaxEntityId(stkMeshDB_->getEdgeRank());
139  GlobalOrdinal maxFaceId = stkMeshDB_->getMaxEntityId(stkMeshDB_->getFaceRank());
140 
141  // compute ID counts for each sub cell type
142  int patternDim = fp.getDimension();
143  switch(patternDim) {
144  case 3:
145  faceIdCnt = fp.getSubcellIndices(2,0).size();
146  // Intentional fall-through.
147  case 2:
148  edgeIdCnt = fp.getSubcellIndices(1,0).size();
149  // Intentional fall-through.
150  case 1:
151  nodeIdCnt = fp.getSubcellIndices(0,0).size();
152  cellIdCnt = fp.getSubcellIndices(patternDim,0).size();
153  break;
154  case 0:
155  default:
156  TEUCHOS_ASSERT(false);
157  };
158 
159  // compute offsets for each sub cell type
160  nodeOffset = 0;
161  edgeOffset = nodeOffset+(maxNodeId+1)*nodeIdCnt;
162  faceOffset = edgeOffset+(maxEdgeId+1)*edgeIdCnt;
163  cellOffset = faceOffset+(maxFaceId+1)*faceIdCnt;
164 
165  // sanity check
166  TEUCHOS_ASSERT(nodeOffset <= edgeOffset
167  && edgeOffset <= faceOffset
168  && faceOffset <= cellOffset);
169 }
170 
173  unsigned subcellRank,
174  LocalOrdinal idCnt,
175  GlobalOrdinal offset,
176  const unsigned maxIds)
177 {
178  if(idCnt<=0)
179  return 0 ;
180 
181  // loop over all relations of specified type, unless requested
182  LocalOrdinal numIds = 0;
183  stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
184  const stk::mesh::EntityRank rank = static_cast<stk::mesh::EntityRank>(subcellRank);
185 
186 #ifdef PANZER_DEBUG
187  TEUCHOS_TEST_FOR_EXCEPTION(maxIds > bulkData.num_connectivity(element, rank),
188  std::runtime_error,
189  "ERROR: The maxIds (num vertices from basis cell topology) is greater than the num vertices in the stk mesh topology!");
190 #endif
191 
192  const size_t num_rels = (maxIds > 0) ? maxIds : bulkData.num_connectivity(element, rank);
193  stk::mesh::Entity const* relations = bulkData.begin(element, rank);
194  for(std::size_t sc=0; sc<num_rels; ++sc) {
195  stk::mesh::Entity subcell = relations[sc];
196 
197  // add connectivities: adjust for STK indexing craziness
198  for(LocalOrdinal i=0;i<idCnt;i++) {
199  connectivity_.push_back(offset+idCnt*(bulkData.identifier(subcell)-1)+i);
200  }
201 
202  numIds += idCnt;
203  }
204  return numIds;
205 }
206 
207 void
209  unsigned subcellRank,unsigned subcellId,GlobalOrdinal newId,
210  GlobalOrdinal offset)
211 {
212  LocalOrdinal elmtLID = stkMeshDB_->elementLocalId(element);
213  auto * conn = this->getConnectivity(elmtLID);
214  const std::vector<int> & subCellIndices = fp.getSubcellIndices(subcellRank,subcellId);
215 
216  // add connectivities: adjust for STK indexing craziness
217  for(std::size_t i=0;i<subCellIndices.size();i++) {
218  conn[subCellIndices[i]] = offset+subCellIndices.size()*(newId-1)+i;
219  }
220 }
221 
223 {
224  PANZER_FUNC_TIME_MONITOR_DIFF("panzer_stk::STKConnManager::buildConnectivity", build_connectivity);
225 
226  stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
227 
228  // get element info from STK_Interface
229  // object and build a local element mapping.
231 
232  // Build sub cell ID counts and offsets
233  // ID counts = How many IDs belong on each subcell (number of mesh DOF used)
234  // Offset = What is starting index for subcell ID type?
235  // Global numbering goes like [node ids, edge ids, face ids, cell ids]
236  LocalOrdinal nodeIdCnt=0, edgeIdCnt=0, faceIdCnt=0, cellIdCnt=0;
237  GlobalOrdinal nodeOffset=0, edgeOffset=0, faceOffset=0, cellOffset=0;
238  buildOffsetsAndIdCounts(fp, nodeIdCnt, edgeIdCnt, faceIdCnt, cellIdCnt,
239  nodeOffset, edgeOffset, faceOffset, cellOffset);
240 
241  // std::cout << "node: count = " << nodeIdCnt << ", offset = " << nodeOffset << std::endl;
242  // std::cout << "edge: count = " << edgeIdCnt << ", offset = " << edgeOffset << std::endl;
243  // std::cout << "face: count = " << faceIdCnt << ", offset = " << faceOffset << std::endl;
244  // std::cout << "cell: count = " << cellIdCnt << ", offset = " << cellOffset << std::endl;
245 
246  // Connectivity only requires lowest order mesh node information
247  // With the notion of extended topologies used by shards, it is
248  // sufficient to take the first num_vertices nodes for connectivity purposes.
249  const unsigned num_vertices = fp.getCellTopology().getVertexCount();
250 
251  // loop over elements and build global connectivity
252  for(std::size_t elmtLid=0;elmtLid!=elements_->size();++elmtLid) {
253  GlobalOrdinal numIds = 0;
254  stk::mesh::Entity element = (*elements_)[elmtLid];
255 
256  // get index into connectivity array
257  elmtLidToConn_[elmtLid] = connectivity_.size();
258 
259  // add connectivities for sub cells
260  // Second order or higher mesh nodes are only needed downstream by the FE bases
261  // The connection manager only expects first order nodes (vertices), so we subselect if necessary
262  // All edge and face IDs are stored
263  numIds += addSubcellConnectivities(element,stkMeshDB_->getNodeRank(),nodeIdCnt,nodeOffset,num_vertices);
264  numIds += addSubcellConnectivities(element,stkMeshDB_->getEdgeRank(),edgeIdCnt,edgeOffset);
265  numIds += addSubcellConnectivities(element,stkMeshDB_->getFaceRank(),faceIdCnt,faceOffset);
266 
267  // add connectivity for parent cells
268  if(cellIdCnt>0) {
269  // add connectivities: adjust for STK indexing craziness
270  for(LocalOrdinal i=0;i<cellIdCnt;i++)
271  connectivity_.push_back(cellOffset+cellIdCnt*(bulkData.identifier(element)-1));
272 
273  numIds += cellIdCnt;
274  }
275 
276  connSize_[elmtLid] = numIds;
277  }
278 
279  applyPeriodicBCs( fp, nodeOffset, edgeOffset, faceOffset, cellOffset);
280 
281  // This method does not modify connectivity_. But it should be called here
282  // because the data it initializes should be available at the same time as
283  // connectivity_.
286 }
287 
289 {
290  // walk through the element blocks and figure out which this ID belongs to
291  stk::mesh::Entity element = (*elements_)[localElmtId];
292 
293  return stkMeshDB_->containingBlockId(element);
294 }
295 
297  GlobalOrdinal faceOffset, GlobalOrdinal /* cellOffset */)
298 {
299  using Teuchos::RCP;
300  using Teuchos::rcp;
301 
302  PANZER_FUNC_TIME_MONITOR_DIFF("panzer_stk::STKConnManager::applyPeriodicBCs", apply_periodic_bcs);
303 
304  std::pair<Teuchos::RCP<std::vector<std::pair<std::size_t,std::size_t> > >, Teuchos::RCP<std::vector<unsigned int> > > matchedValues
305  = stkMeshDB_->getPeriodicNodePairing();
306 
308  = matchedValues.first;
310  = matchedValues.second;
311 
312  // no matchedNodes means nothing to do!
313  if(matchedNodes==Teuchos::null) return;
314 
315  for(std::size_t m=0;m<matchedNodes->size();m++) {
316  stk::mesh::EntityId oldNodeId = (*matchedNodes)[m].first;
317  std::size_t newNodeId = (*matchedNodes)[m].second;
318 
319  std::vector<stk::mesh::Entity> elements;
320  std::vector<int> localIds;
321 
322  GlobalOrdinal offset0 = 0; // to make numbering consistent with that in PeriodicBC_Matcher
323  GlobalOrdinal offset1 = 0; // offset for dof indexing
324  if((*matchTypes)[m] == 0)
325  offset1 = nodeOffset-offset0;
326  else if((*matchTypes)[m] == 1){
327  offset0 = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank());
328  offset1 = edgeOffset-offset0;
329  } else if((*matchTypes)[m] == 2){
330  offset0 = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank())+stkMeshDB_->getMaxEntityId(stkMeshDB_->getEdgeRank());
331  offset1 = faceOffset-offset0;
332  } else
333  TEUCHOS_ASSERT(false);
334 
335  // get relevent elements and node IDs
336  stkMeshDB_->getOwnedElementsSharingNode(stk::mesh::EntityId(oldNodeId-offset0),elements,localIds,(*matchTypes)[m]);
337 
338  // modify global numbering already built for each element
339  for(std::size_t e=0;e<elements.size();e++){
340  modifySubcellConnectivities(fp,elements[e],(*matchTypes)[m],localIds[e],newNodeId,offset1);
341  }
342 
343  }
344 }
345 
348 void STKConnManager::getDofCoords(const std::string & blockId,
349  const panzer::Intrepid2FieldPattern & coordProvider,
350  std::vector<std::size_t> & localCellIds,
351  Kokkos::DynRankView<double,PHX::Device> & points) const
352 {
353  int dim = coordProvider.getDimension();
354  int numIds = coordProvider.numberIds();
355 
356  // grab element nodes
357  Kokkos::DynRankView<double,PHX::Device> nodes;
358  workset_utils::getIdsAndNodes(*stkMeshDB_,blockId,localCellIds,nodes);
359 
360  // setup output array
361  points = Kokkos::DynRankView<double,PHX::Device>("points",localCellIds.size(),numIds,dim);
362  coordProvider.getInterpolatoryCoordinates(nodes,points,stkMeshDB_->getCellTopology(blockId));
363 }
364 
366 {
367  return ! sidesetsToAssociate_.empty();
368 }
369 
370 void STKConnManager::associateElementsInSideset(const std::string sideset_id)
371 {
372  sidesetsToAssociate_.push_back(sideset_id);
373  sidesetYieldedAssociations_.push_back(false);
374 }
375 
376 inline std::size_t
377 getElementIdx(const std::vector<stk::mesh::Entity>& elements,
378  stk::mesh::Entity const e)
379 {
380  return static_cast<std::size_t>(
381  std::distance(elements.begin(), std::find(elements.begin(), elements.end(), e)));
382 }
383 
385 {
386  stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
387  elmtToAssociatedElmts_.resize(elements_->size());
388  for (std::size_t i = 0; i < sidesetsToAssociate_.size(); ++i) {
389  std::vector<stk::mesh::Entity> sides;
390  stkMeshDB_->getAllSides(sidesetsToAssociate_[i], sides);
391  sidesetYieldedAssociations_[i] = ! sides.empty();
392  for (std::vector<stk::mesh::Entity>::const_iterator si = sides.begin();
393  si != sides.end(); ++si) {
394  stk::mesh::Entity side = *si;
395  const size_t num_elements = bulkData.num_elements(side);
396  stk::mesh::Entity const* elements = bulkData.begin_elements(side);
397  if (num_elements != 2) {
398  // If relations.size() != 2 for one side in the sideset, then it's true
399  // for all, including the first.
400  TEUCHOS_ASSERT(si == sides.begin());
401  sidesetYieldedAssociations_[i] = false;
402  break;
403  }
404  const std::size_t ea_id = getElementIdx(*elements_, elements[0]),
405  eb_id = getElementIdx(*elements_, elements[1]);
406  elmtToAssociatedElmts_[ea_id].push_back(eb_id);
407  elmtToAssociatedElmts_[eb_id].push_back(ea_id);
408  }
409  }
410 }
411 
412 std::vector<std::string> STKConnManager::
414 {
415  std::vector<std::string> sidesets;
416  for (std::size_t i = 0; i < sidesetYieldedAssociations_.size(); ++i) {
417  int sya, my_sya = sidesetYieldedAssociations_[i] ? 1 : 0;
418  Teuchos::reduceAll(comm, Teuchos::REDUCE_MAX, 1, &my_sya, &sya);
419  if (sya == 0)
420  sidesets.push_back(sidesetsToAssociate_[i]);
421  }
422  return sidesets;
423 }
424 
425 const std::vector<STKConnManager::LocalOrdinal>&
427 {
428  return elmtToAssociatedElmts_[el];
429 }
430 
431 }
virtual int getDimension() const =0
std::map< std::string, Teuchos::RCP< std::vector< LocalOrdinal > > > elementBlocks_
virtual const std::vector< LocalOrdinal > & getAssociatedNeighbors(const LocalOrdinal &el) const
virtual std::string getBlockId(LocalOrdinal localElmtId) const
panzer::ConnManager::GlobalOrdinal GlobalOrdinal
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
std::vector< bool > sidesetYieldedAssociations_
std::map< std::string, Teuchos::RCP< std::vector< LocalOrdinal > > > neighborElementBlocks_
Teuchos::RCP< const STK_Interface > stkMeshDB_
std::vector< GlobalOrdinal > connectivity_
void getIdsAndNodes(const panzer_stk::STK_Interface &mesh, std::string blockId, std::vector< std::size_t > &localIds, ArrayT &nodes)
virtual bool hasAssociatedNeighbors() const
std::vector< std::string > checkAssociateElementsInSidesets(const Teuchos::Comm< int > &comm) const
std::vector< std::vector< LocalOrdinal > > elmtToAssociatedElmts_
virtual int numberIds() const
virtual const panzer::GlobalOrdinal * getConnectivity(LocalOrdinal localElmtId) const
void buildOffsetsAndIdCounts(const panzer::FieldPattern &fp, LocalOrdinal &nodeIdCnt, LocalOrdinal &edgeIdCnt, LocalOrdinal &faceIdCnt, LocalOrdinal &cellIdCnt, GlobalOrdinal &nodeOffset, GlobalOrdinal &edgeOffset, GlobalOrdinal &faceOffset, GlobalOrdinal &cellOffset) const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual Teuchos::RCP< panzer::ConnManager > noConnectivityClone() const
void modifySubcellConnectivities(const panzer::FieldPattern &fp, stk::mesh::Entity element, unsigned subcellRank, unsigned subcellId, GlobalOrdinal newId, GlobalOrdinal offset)
void applyPeriodicBCs(const panzer::FieldPattern &fp, GlobalOrdinal nodeOffset, GlobalOrdinal edgeOffset, GlobalOrdinal faceOffset, GlobalOrdinal cellOffset)
panzer::ConnManager::LocalOrdinal LocalOrdinal
LocalOrdinal addSubcellConnectivities(stk::mesh::Entity element, unsigned subcellRank, LocalOrdinal idCnt, GlobalOrdinal offset, const unsigned maxIds=0)
Loops over relations of a given rank for a specified element and adds a unique ID to the connectivity...
virtual void getDofCoords(const std::string &blockId, const panzer::Intrepid2FieldPattern &coordProvider, std::vector< std::size_t > &localCellIds, Kokkos::DynRankView< double, PHX::Device > &points) const
std::vector< LocalOrdinal > elmtLidToConn_
std::vector< std::string > sidesetsToAssociate_
virtual shards::CellTopology getCellTopology() const =0
void getInterpolatoryCoordinates(Kokkos::DynRankView< double, PHX::Device > &coords) const
virtual const std::vector< int > & getSubcellIndices(int dim, int cellIndex) const =0
#define TEUCHOS_ASSERT(assertion_test)
Teuchos::RCP< std::vector< stk::mesh::Entity > > elements_
std::size_t getElementIdx(const std::vector< stk::mesh::Entity > &elements, stk::mesh::Entity const e)
virtual void buildConnectivity(const panzer::FieldPattern &fp)
STKConnManager(const Teuchos::RCP< const STK_Interface > &stkMeshDB)
void associateElementsInSideset(const std::string sideset_id)
std::vector< LocalOrdinal > connSize_