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 //
4 // Panzer: A partial differential equation assembly
5 // engine for strongly coupled complex multiphysics systems
6 // Copyright (2011) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Roger P. Pawlowski (rppawlo@sandia.gov) and
39 // Eric C. Cyr (eccyr@sandia.gov)
40 // ***********************************************************************
41 // @HEADER
42 
44 
45 #include <vector>
46 
47 // Teuchos includes
48 #include "Teuchos_RCP.hpp"
49 
50 #include "Kokkos_DynRankView.hpp"
51 
56 
57 #include "Teuchos_FancyOStream.hpp"
58 
59 namespace panzer_stk {
60 
61 using Teuchos::RCP;
62 using Teuchos::rcp;
63 
64 // Object describing how to sort a vector of elements using
65 // local ID as the key
66 class LocalIdCompare {
67 public:
68  LocalIdCompare(const RCP<const STK_Interface> & mesh) : mesh_(mesh) {}
69 
70  // Compares two stk mesh entities based on local ID
71  bool operator() (stk::mesh::Entity a,stk::mesh::Entity b)
72  { return mesh_->elementLocalId(a) < mesh_->elementLocalId(b);}
73 
74 private:
75  RCP<const STK_Interface> mesh_;
76 };
77 
79  : stkMeshDB_(stkMeshDB), ownedElementCount_(0)
80 {
81 }
82 
85 {
87 }
88 
90 {
91  elements_ = Teuchos::null;
92 
93  elementBlocks_.clear();
94  elmtLidToConn_.clear();
95  connSize_.clear();
96  elmtToAssociatedElmts_.clear();
97 }
98 
100 {
101  clearLocalElementMapping(); // forget the past
102 
103  // build element block information
105  elements_ = Teuchos::rcp(new std::vector<stk::mesh::Entity>);
106 
107  // defines ordering of blocks
108  std::vector<std::string> blockIds;
109  stkMeshDB_->getElementBlockNames(blockIds);
110 
111  std::size_t blockIndex=0;
112  for(std::vector<std::string>::const_iterator idItr=blockIds.begin();
113  idItr!=blockIds.end();++idItr,++blockIndex) {
114  std::string blockId = *idItr;
115 
116  // grab elements on this block
117  std::vector<stk::mesh::Entity> blockElmts;
118  stkMeshDB_->getMyElements(blockId,blockElmts);
119 
120  // concatenate them into element LID lookup table
121  elements_->insert(elements_->end(),blockElmts.begin(),blockElmts.end());
122 
123  // build block to LID map
124  elementBlocks_[blockId] = Teuchos::rcp(new std::vector<LocalOrdinal>);
125  for(std::size_t i=0;i<blockElmts.size();i++)
126  elementBlocks_[blockId]->push_back(stkMeshDB_->elementLocalId(blockElmts[i]));
127  }
128 
129  ownedElementCount_ = elements_->size();
130 
131  blockIndex=0;
132  for(std::vector<std::string>::const_iterator idItr=blockIds.begin();
133  idItr!=blockIds.end();++idItr,++blockIndex) {
134  std::string blockId = *idItr;
135 
136  // grab elements on this block
137  std::vector<stk::mesh::Entity> blockElmts;
138  stkMeshDB_->getNeighborElements(blockId,blockElmts);
139 
140  // concatenate them into element LID lookup table
141  elements_->insert(elements_->end(),blockElmts.begin(),blockElmts.end());
142 
143  // build block to LID map
144  neighborElementBlocks_[blockId] = Teuchos::rcp(new std::vector<LocalOrdinal>);
145  for(std::size_t i=0;i<blockElmts.size();i++)
146  neighborElementBlocks_[blockId]->push_back(stkMeshDB_->elementLocalId(blockElmts[i]));
147  }
148 
149  // this expensive operation gurantees ordering of local IDs
150  std::sort(elements_->begin(),elements_->end(),LocalIdCompare(stkMeshDB_));
151 
152  // allocate space for element LID to Connectivty map
153  // connectivity size
154  elmtLidToConn_.clear();
155  elmtLidToConn_.resize(elements_->size(),0);
156 
157  connSize_.clear();
158  connSize_.resize(elements_->size(),0);
159 }
160 
161 void
163  LocalOrdinal & nodeIdCnt, LocalOrdinal & edgeIdCnt,
164  LocalOrdinal & faceIdCnt, LocalOrdinal & cellIdCnt,
165  GlobalOrdinal & nodeOffset, GlobalOrdinal & edgeOffset,
166  GlobalOrdinal & faceOffset, GlobalOrdinal & cellOffset) const
167 {
168  // get the global counts for all the nodes, faces, edges and cells
169  GlobalOrdinal maxNodeId = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank());
170  GlobalOrdinal maxEdgeId = stkMeshDB_->getMaxEntityId(stkMeshDB_->getEdgeRank());
171  GlobalOrdinal maxFaceId = stkMeshDB_->getMaxEntityId(stkMeshDB_->getFaceRank());
172 
173  // compute ID counts for each sub cell type
174  int patternDim = fp.getDimension();
175  switch(patternDim) {
176  case 3:
177  faceIdCnt = fp.getSubcellIndices(2,0).size();
178  // Intentional fall-through.
179  case 2:
180  edgeIdCnt = fp.getSubcellIndices(1,0).size();
181  // Intentional fall-through.
182  case 1:
183  nodeIdCnt = fp.getSubcellIndices(0,0).size();
184  cellIdCnt = fp.getSubcellIndices(patternDim,0).size();
185  break;
186  case 0:
187  default:
188  TEUCHOS_ASSERT(false);
189  };
190 
191  // compute offsets for each sub cell type
192  nodeOffset = 0;
193  edgeOffset = nodeOffset+(maxNodeId+1)*nodeIdCnt;
194  faceOffset = edgeOffset+(maxEdgeId+1)*edgeIdCnt;
195  cellOffset = faceOffset+(maxFaceId+1)*faceIdCnt;
196 
197  // sanity check
198  TEUCHOS_ASSERT(nodeOffset <= edgeOffset
199  && edgeOffset <= faceOffset
200  && faceOffset <= cellOffset);
201 }
202 
205  unsigned subcellRank,
206  LocalOrdinal idCnt,
207  GlobalOrdinal offset,
208  const unsigned maxIds)
209 {
210  if(idCnt<=0)
211  return 0 ;
212 
213  // loop over all relations of specified type, unless requested
214  LocalOrdinal numIds = 0;
215  stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
216  const stk::mesh::EntityRank rank = static_cast<stk::mesh::EntityRank>(subcellRank);
217 
218 #ifdef PANZER_DEBUG
219  TEUCHOS_TEST_FOR_EXCEPTION(maxIds > bulkData.num_connectivity(element, rank),
220  std::runtime_error,
221  "ERROR: The maxIds (num vertices from basis cell topology) is greater than the num vertices in the stk mesh topology!");
222 #endif
223 
224  const size_t num_rels = (maxIds > 0) ? maxIds : bulkData.num_connectivity(element, rank);
225  stk::mesh::Entity const* relations = bulkData.begin(element, rank);
226  for(std::size_t sc=0; sc<num_rels; ++sc) {
227  stk::mesh::Entity subcell = relations[sc];
228 
229  // add connectivities: adjust for STK indexing craziness
230  for(LocalOrdinal i=0;i<idCnt;i++) {
231  connectivity_.push_back(offset+idCnt*(bulkData.identifier(subcell)-1)+i);
232  }
233 
234  numIds += idCnt;
235  }
236  return numIds;
237 }
238 
239 void
241  unsigned subcellRank,unsigned subcellId,GlobalOrdinal newId,
242  GlobalOrdinal offset)
243 {
244  LocalOrdinal elmtLID = stkMeshDB_->elementLocalId(element);
245  auto * conn = this->getConnectivity(elmtLID);
246  const std::vector<int> & subCellIndices = fp.getSubcellIndices(subcellRank,subcellId);
247 
248  // add connectivities: adjust for STK indexing craziness
249  for(std::size_t i=0;i<subCellIndices.size();i++) {
250  conn[subCellIndices[i]] = offset+subCellIndices.size()*(newId-1)+i;
251  }
252 }
253 
255 {
256 #ifdef HAVE_EXTRA_TIMERS
257  using Teuchos::TimeMonitor;
258  RCP<Teuchos::TimeMonitor> tM = rcp(new TimeMonitor(*TimeMonitor::getNewTimer(std::string("panzer_stk::STKConnManager::buildConnectivity"))));
259 #endif
260 
261  stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
262 
263  // get element info from STK_Interface
264  // object and build a local element mapping.
266 
267  // Build sub cell ID counts and offsets
268  // ID counts = How many IDs belong on each subcell (number of mesh DOF used)
269  // Offset = What is starting index for subcell ID type?
270  // Global numbering goes like [node ids, edge ids, face ids, cell ids]
271  LocalOrdinal nodeIdCnt=0, edgeIdCnt=0, faceIdCnt=0, cellIdCnt=0;
272  GlobalOrdinal nodeOffset=0, edgeOffset=0, faceOffset=0, cellOffset=0;
273  buildOffsetsAndIdCounts(fp, nodeIdCnt, edgeIdCnt, faceIdCnt, cellIdCnt,
274  nodeOffset, edgeOffset, faceOffset, cellOffset);
275 
276  // std::cout << "node: count = " << nodeIdCnt << ", offset = " << nodeOffset << std::endl;
277  // std::cout << "edge: count = " << edgeIdCnt << ", offset = " << edgeOffset << std::endl;
278  // std::cout << "face: count = " << faceIdCnt << ", offset = " << faceOffset << std::endl;
279  // std::cout << "cell: count = " << cellIdCnt << ", offset = " << cellOffset << std::endl;
280 
281  // Connectivity only requires lowest order mesh node information
282  // With the notion of extended topologies used by shards, it is
283  // sufficient to take the first num_vertices nodes for connectivity purposes.
284  const unsigned num_vertices = fp.getCellTopology().getVertexCount();
285 
286  // loop over elements and build global connectivity
287  for(std::size_t elmtLid=0;elmtLid!=elements_->size();++elmtLid) {
288  GlobalOrdinal numIds = 0;
289  stk::mesh::Entity element = (*elements_)[elmtLid];
290 
291  // get index into connectivity array
292  elmtLidToConn_[elmtLid] = connectivity_.size();
293 
294  // add connectivities for sub cells
295  // Second order or higher mesh nodes are only needed downstream by the FE bases
296  // The connection manager only expects first order nodes (vertices), so we subselect if necessary
297  // All edge and face IDs are stored
298  numIds += addSubcellConnectivities(element,stkMeshDB_->getNodeRank(),nodeIdCnt,nodeOffset,num_vertices);
299  numIds += addSubcellConnectivities(element,stkMeshDB_->getEdgeRank(),edgeIdCnt,edgeOffset);
300  numIds += addSubcellConnectivities(element,stkMeshDB_->getFaceRank(),faceIdCnt,faceOffset);
301 
302  // add connectivity for parent cells
303  if(cellIdCnt>0) {
304  // add connectivities: adjust for STK indexing craziness
305  for(LocalOrdinal i=0;i<cellIdCnt;i++)
306  connectivity_.push_back(cellOffset+cellIdCnt*(bulkData.identifier(element)-1));
307 
308  numIds += cellIdCnt;
309  }
310 
311  connSize_[elmtLid] = numIds;
312  }
313 
314  applyPeriodicBCs( fp, nodeOffset, edgeOffset, faceOffset, cellOffset);
315 
316  // This method does not modify connectivity_. But it should be called here
317  // because the data it initializes should be available at the same time as
318  // connectivity_.
321 }
322 
324 {
325  // walk through the element blocks and figure out which this ID belongs to
326  stk::mesh::Entity element = (*elements_)[localElmtId];
327 
328  return stkMeshDB_->containingBlockId(element);
329 }
330 
332  GlobalOrdinal faceOffset, GlobalOrdinal /* cellOffset */)
333 {
334  using Teuchos::RCP;
335  using Teuchos::rcp;
336 
337 #ifdef HAVE_EXTRA_TIMERS
338  using Teuchos::TimeMonitor;
339  RCP<Teuchos::TimeMonitor> tM = rcp(new TimeMonitor(*TimeMonitor::getNewTimer(std::string("panzer_stk::STKConnManager::applyPeriodicBCs"))));
340 #endif
341 
342  std::pair<Teuchos::RCP<std::vector<std::pair<std::size_t,std::size_t> > >, Teuchos::RCP<std::vector<unsigned int> > > matchedValues
343  = stkMeshDB_->getPeriodicNodePairing();
344 
346  = matchedValues.first;
348  = matchedValues.second;
349 
350  // no matchedNodes means nothing to do!
351  if(matchedNodes==Teuchos::null) return;
352 
353  for(std::size_t m=0;m<matchedNodes->size();m++) {
354  stk::mesh::EntityId oldNodeId = (*matchedNodes)[m].first;
355  std::size_t newNodeId = (*matchedNodes)[m].second;
356 
357  std::vector<stk::mesh::Entity> elements;
358  std::vector<int> localIds;
359 
360  GlobalOrdinal offset0 = 0; // to make numbering consistent with that in PeriodicBC_Matcher
361  GlobalOrdinal offset1 = 0; // offset for dof indexing
362  if((*matchTypes)[m] == 0)
363  offset1 = nodeOffset-offset0;
364  else if((*matchTypes)[m] == 1){
365  offset0 = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank());
366  offset1 = edgeOffset-offset0;
367  } else if((*matchTypes)[m] == 2){
368  offset0 = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank())+stkMeshDB_->getMaxEntityId(stkMeshDB_->getEdgeRank());
369  offset1 = faceOffset-offset0;
370  } else
371  TEUCHOS_ASSERT(false);
372 
373  // get relevent elements and node IDs
374  stkMeshDB_->getOwnedElementsSharingNode(stk::mesh::EntityId(oldNodeId-offset0),elements,localIds,(*matchTypes)[m]);
375 
376  // modify global numbering already built for each element
377  for(std::size_t e=0;e<elements.size();e++){
378  modifySubcellConnectivities(fp,elements[e],(*matchTypes)[m],localIds[e],newNodeId,offset1);
379  }
380 
381  }
382 }
383 
386 void STKConnManager::getDofCoords(const std::string & blockId,
387  const panzer::Intrepid2FieldPattern & coordProvider,
388  std::vector<std::size_t> & localCellIds,
389  Kokkos::DynRankView<double,PHX::Device> & points) const
390 {
391  int dim = coordProvider.getDimension();
392  int numIds = coordProvider.numberIds();
393 
394  // grab element nodes
395  Kokkos::DynRankView<double,PHX::Device> nodes;
396  workset_utils::getIdsAndNodes(*stkMeshDB_,blockId,localCellIds,nodes);
397 
398  // setup output array
399  points = Kokkos::DynRankView<double,PHX::Device>("points",localCellIds.size(),numIds,dim);
400  coordProvider.getInterpolatoryCoordinates(nodes,points,stkMeshDB_->getCellTopology(blockId));
401 }
402 
404 {
405  return ! sidesetsToAssociate_.empty();
406 }
407 
408 void STKConnManager::associateElementsInSideset(const std::string sideset_id)
409 {
410  sidesetsToAssociate_.push_back(sideset_id);
411  sidesetYieldedAssociations_.push_back(false);
412 }
413 
414 inline std::size_t
415 getElementIdx(const std::vector<stk::mesh::Entity>& elements,
416  stk::mesh::Entity const e)
417 {
418  return static_cast<std::size_t>(
419  std::distance(elements.begin(), std::find(elements.begin(), elements.end(), e)));
420 }
421 
423 {
424  stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
425  elmtToAssociatedElmts_.resize(elements_->size());
426  for (std::size_t i = 0; i < sidesetsToAssociate_.size(); ++i) {
427  std::vector<stk::mesh::Entity> sides;
428  stkMeshDB_->getAllSides(sidesetsToAssociate_[i], sides);
429  sidesetYieldedAssociations_[i] = ! sides.empty();
430  for (std::vector<stk::mesh::Entity>::const_iterator si = sides.begin();
431  si != sides.end(); ++si) {
432  stk::mesh::Entity side = *si;
433  const size_t num_elements = bulkData.num_elements(side);
434  stk::mesh::Entity const* elements = bulkData.begin_elements(side);
435  if (num_elements != 2) {
436  // If relations.size() != 2 for one side in the sideset, then it's true
437  // for all, including the first.
438  TEUCHOS_ASSERT(si == sides.begin());
439  sidesetYieldedAssociations_[i] = false;
440  break;
441  }
442  const std::size_t ea_id = getElementIdx(*elements_, elements[0]),
443  eb_id = getElementIdx(*elements_, elements[1]);
444  elmtToAssociatedElmts_[ea_id].push_back(eb_id);
445  elmtToAssociatedElmts_[eb_id].push_back(ea_id);
446  }
447  }
448 }
449 
450 std::vector<std::string> STKConnManager::
452 {
453  std::vector<std::string> sidesets;
454  for (std::size_t i = 0; i < sidesetYieldedAssociations_.size(); ++i) {
455  int sya, my_sya = sidesetYieldedAssociations_[i] ? 1 : 0;
456  Teuchos::reduceAll(comm, Teuchos::REDUCE_MAX, 1, &my_sya, &sya);
457  if (sya == 0)
458  sidesets.push_back(sidesetsToAssociate_[i]);
459  }
460  return sidesets;
461 }
462 
463 const std::vector<STKConnManager::LocalOrdinal>&
465 {
466  return elmtToAssociatedElmts_[el];
467 }
468 
469 }
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_