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 #ifdef HAVE_EXTRA_TIMERS
225  using Teuchos::TimeMonitor;
226  RCP<Teuchos::TimeMonitor> tM = rcp(new TimeMonitor(*TimeMonitor::getNewTimer(std::string("panzer_stk::STKConnManager::buildConnectivity"))));
227 #endif
228 
229  stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
230 
231  // get element info from STK_Interface
232  // object and build a local element mapping.
234 
235  // Build sub cell ID counts and offsets
236  // ID counts = How many IDs belong on each subcell (number of mesh DOF used)
237  // Offset = What is starting index for subcell ID type?
238  // Global numbering goes like [node ids, edge ids, face ids, cell ids]
239  LocalOrdinal nodeIdCnt=0, edgeIdCnt=0, faceIdCnt=0, cellIdCnt=0;
240  GlobalOrdinal nodeOffset=0, edgeOffset=0, faceOffset=0, cellOffset=0;
241  buildOffsetsAndIdCounts(fp, nodeIdCnt, edgeIdCnt, faceIdCnt, cellIdCnt,
242  nodeOffset, edgeOffset, faceOffset, cellOffset);
243 
244  // std::cout << "node: count = " << nodeIdCnt << ", offset = " << nodeOffset << std::endl;
245  // std::cout << "edge: count = " << edgeIdCnt << ", offset = " << edgeOffset << std::endl;
246  // std::cout << "face: count = " << faceIdCnt << ", offset = " << faceOffset << std::endl;
247  // std::cout << "cell: count = " << cellIdCnt << ", offset = " << cellOffset << std::endl;
248 
249  // Connectivity only requires lowest order mesh node information
250  // With the notion of extended topologies used by shards, it is
251  // sufficient to take the first num_vertices nodes for connectivity purposes.
252  const unsigned num_vertices = fp.getCellTopology().getVertexCount();
253 
254  // loop over elements and build global connectivity
255  for(std::size_t elmtLid=0;elmtLid!=elements_->size();++elmtLid) {
256  GlobalOrdinal numIds = 0;
257  stk::mesh::Entity element = (*elements_)[elmtLid];
258 
259  // get index into connectivity array
260  elmtLidToConn_[elmtLid] = connectivity_.size();
261 
262  // add connectivities for sub cells
263  // Second order or higher mesh nodes are only needed downstream by the FE bases
264  // The connection manager only expects first order nodes (vertices), so we subselect if necessary
265  // All edge and face IDs are stored
266  numIds += addSubcellConnectivities(element,stkMeshDB_->getNodeRank(),nodeIdCnt,nodeOffset,num_vertices);
267  numIds += addSubcellConnectivities(element,stkMeshDB_->getEdgeRank(),edgeIdCnt,edgeOffset);
268  numIds += addSubcellConnectivities(element,stkMeshDB_->getFaceRank(),faceIdCnt,faceOffset);
269 
270  // add connectivity for parent cells
271  if(cellIdCnt>0) {
272  // add connectivities: adjust for STK indexing craziness
273  for(LocalOrdinal i=0;i<cellIdCnt;i++)
274  connectivity_.push_back(cellOffset+cellIdCnt*(bulkData.identifier(element)-1));
275 
276  numIds += cellIdCnt;
277  }
278 
279  connSize_[elmtLid] = numIds;
280  }
281 
282  applyPeriodicBCs( fp, nodeOffset, edgeOffset, faceOffset, cellOffset);
283 
284  // This method does not modify connectivity_. But it should be called here
285  // because the data it initializes should be available at the same time as
286  // connectivity_.
289 }
290 
292 {
293  // walk through the element blocks and figure out which this ID belongs to
294  stk::mesh::Entity element = (*elements_)[localElmtId];
295 
296  return stkMeshDB_->containingBlockId(element);
297 }
298 
300  GlobalOrdinal faceOffset, GlobalOrdinal /* cellOffset */)
301 {
302  using Teuchos::RCP;
303  using Teuchos::rcp;
304 
305 #ifdef HAVE_EXTRA_TIMERS
306  using Teuchos::TimeMonitor;
307  RCP<Teuchos::TimeMonitor> tM = rcp(new TimeMonitor(*TimeMonitor::getNewTimer(std::string("panzer_stk::STKConnManager::applyPeriodicBCs"))));
308 #endif
309 
310  std::pair<Teuchos::RCP<std::vector<std::pair<std::size_t,std::size_t> > >, Teuchos::RCP<std::vector<unsigned int> > > matchedValues
311  = stkMeshDB_->getPeriodicNodePairing();
312 
314  = matchedValues.first;
316  = matchedValues.second;
317 
318  // no matchedNodes means nothing to do!
319  if(matchedNodes==Teuchos::null) return;
320 
321  for(std::size_t m=0;m<matchedNodes->size();m++) {
322  stk::mesh::EntityId oldNodeId = (*matchedNodes)[m].first;
323  std::size_t newNodeId = (*matchedNodes)[m].second;
324 
325  std::vector<stk::mesh::Entity> elements;
326  std::vector<int> localIds;
327 
328  GlobalOrdinal offset0 = 0; // to make numbering consistent with that in PeriodicBC_Matcher
329  GlobalOrdinal offset1 = 0; // offset for dof indexing
330  if((*matchTypes)[m] == 0)
331  offset1 = nodeOffset-offset0;
332  else if((*matchTypes)[m] == 1){
333  offset0 = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank());
334  offset1 = edgeOffset-offset0;
335  } else if((*matchTypes)[m] == 2){
336  offset0 = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank())+stkMeshDB_->getMaxEntityId(stkMeshDB_->getEdgeRank());
337  offset1 = faceOffset-offset0;
338  } else
339  TEUCHOS_ASSERT(false);
340 
341  // get relevent elements and node IDs
342  stkMeshDB_->getOwnedElementsSharingNode(stk::mesh::EntityId(oldNodeId-offset0),elements,localIds,(*matchTypes)[m]);
343 
344  // modify global numbering already built for each element
345  for(std::size_t e=0;e<elements.size();e++){
346  modifySubcellConnectivities(fp,elements[e],(*matchTypes)[m],localIds[e],newNodeId,offset1);
347  }
348 
349  }
350 }
351 
354 void STKConnManager::getDofCoords(const std::string & blockId,
355  const panzer::Intrepid2FieldPattern & coordProvider,
356  std::vector<std::size_t> & localCellIds,
357  Kokkos::DynRankView<double,PHX::Device> & points) const
358 {
359  int dim = coordProvider.getDimension();
360  int numIds = coordProvider.numberIds();
361 
362  // grab element nodes
363  Kokkos::DynRankView<double,PHX::Device> nodes;
364  workset_utils::getIdsAndNodes(*stkMeshDB_,blockId,localCellIds,nodes);
365 
366  // setup output array
367  points = Kokkos::DynRankView<double,PHX::Device>("points",localCellIds.size(),numIds,dim);
368  coordProvider.getInterpolatoryCoordinates(nodes,points,stkMeshDB_->getCellTopology(blockId));
369 }
370 
372 {
373  return ! sidesetsToAssociate_.empty();
374 }
375 
376 void STKConnManager::associateElementsInSideset(const std::string sideset_id)
377 {
378  sidesetsToAssociate_.push_back(sideset_id);
379  sidesetYieldedAssociations_.push_back(false);
380 }
381 
382 inline std::size_t
383 getElementIdx(const std::vector<stk::mesh::Entity>& elements,
384  stk::mesh::Entity const e)
385 {
386  return static_cast<std::size_t>(
387  std::distance(elements.begin(), std::find(elements.begin(), elements.end(), e)));
388 }
389 
391 {
392  stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
393  elmtToAssociatedElmts_.resize(elements_->size());
394  for (std::size_t i = 0; i < sidesetsToAssociate_.size(); ++i) {
395  std::vector<stk::mesh::Entity> sides;
396  stkMeshDB_->getAllSides(sidesetsToAssociate_[i], sides);
397  sidesetYieldedAssociations_[i] = ! sides.empty();
398  for (std::vector<stk::mesh::Entity>::const_iterator si = sides.begin();
399  si != sides.end(); ++si) {
400  stk::mesh::Entity side = *si;
401  const size_t num_elements = bulkData.num_elements(side);
402  stk::mesh::Entity const* elements = bulkData.begin_elements(side);
403  if (num_elements != 2) {
404  // If relations.size() != 2 for one side in the sideset, then it's true
405  // for all, including the first.
406  TEUCHOS_ASSERT(si == sides.begin());
407  sidesetYieldedAssociations_[i] = false;
408  break;
409  }
410  const std::size_t ea_id = getElementIdx(*elements_, elements[0]),
411  eb_id = getElementIdx(*elements_, elements[1]);
412  elmtToAssociatedElmts_[ea_id].push_back(eb_id);
413  elmtToAssociatedElmts_[eb_id].push_back(ea_id);
414  }
415  }
416 }
417 
418 std::vector<std::string> STKConnManager::
420 {
421  std::vector<std::string> sidesets;
422  for (std::size_t i = 0; i < sidesetYieldedAssociations_.size(); ++i) {
423  int sya, my_sya = sidesetYieldedAssociations_[i] ? 1 : 0;
424  Teuchos::reduceAll(comm, Teuchos::REDUCE_MAX, 1, &my_sya, &sya);
425  if (sya == 0)
426  sidesets.push_back(sidesetsToAssociate_[i]);
427  }
428  return sidesets;
429 }
430 
431 const std::vector<STKConnManager::LocalOrdinal>&
433 {
434  return elmtToAssociatedElmts_[el];
435 }
436 
437 }
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_