Panzer Version of the Day
Loading...
Searching...
No Matches
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 <algorithm>
14#include <vector>
15
16// Teuchos includes
17#include "Teuchos_RCP.hpp"
18
19#include "Kokkos_DynRankView.hpp"
20
25
26#include "Teuchos_FancyOStream.hpp"
27
28namespace panzer_stk {
29
30using Teuchos::RCP;
31using Teuchos::rcp;
32
33// Initialize statics
35std::vector<STKConnManager::CachedEntry> STKConnManager::cached_conn_managers_{};
37
38void STKConnManager::clearCachedConnectivityData(const Teuchos::RCP<const STK_Interface>& mesh)
39{
40 PANZER_FUNC_TIME_MONITOR("panzer::ConnectivityManager::clearCachedConnectivityData()");
41 const STK_Interface* mesh_ptr = mesh.get();
42 cached_conn_managers_.erase(std::remove_if(cached_conn_managers_.begin(),
44 [mesh_ptr](const CachedEntry& entry)
45 { return entry.second->stkMeshDB_.get() == mesh_ptr; }),
47}
48
49// Object describing how to sort a vector of elements using
50// local ID as the key
51class LocalIdCompare {
52public:
53 LocalIdCompare(const RCP<const STK_Interface> & mesh) : mesh_(mesh) {}
54
55 // Compares two stk mesh entities based on local ID
56 bool operator() (stk::mesh::Entity a,stk::mesh::Entity b)
57 { return mesh_->elementLocalId(a) < mesh_->elementLocalId(b);}
58
59private:
60 RCP<const STK_Interface> mesh_;
61};
62
63STKConnManager::STKConnManager(const Teuchos::RCP<const STK_Interface> & stkMeshDB)
64 : stkMeshDB_(stkMeshDB),
65 elmtLidToConnPtr_(Teuchos::rcp(new std::vector<LocalOrdinal>)),
66 connSizePtr_(Teuchos::rcp(new std::vector<LocalOrdinal>)),
67 connectivityPtr_(Teuchos::rcp(new std::vector<GlobalOrdinal>)),
69 elmtToAssociatedElmtsPtr_(Teuchos::rcp(new std::vector<std::vector<LocalOrdinal> >))
70{
71}
72
87
88Teuchos::RCP<panzer::ConnManager>
90{
91 return Teuchos::rcp(new STKConnManager(stkMeshDB_));
92}
93
95{
96 elements_ = Teuchos::null;
97
98 elementBlocks_.clear();
99
100 // Allocate new arrays rather than clearing in place: the old arrays may be
101 // shared with the connectivity cache or with other STKConnManagers.
102 elmtLidToConnPtr_ = Teuchos::rcp(new std::vector<LocalOrdinal>);
103 connSizePtr_ = Teuchos::rcp(new std::vector<LocalOrdinal>);
104 connectivityPtr_ = Teuchos::rcp(new std::vector<GlobalOrdinal>);
105 elmtToAssociatedElmtsPtr_ = Teuchos::rcp(new std::vector<std::vector<LocalOrdinal> >);
106}
107
109{
110 clearLocalElementMapping(); // forget the past
111
112 // build element block information
114 elements_ = Teuchos::rcp(new std::vector<stk::mesh::Entity>);
115
116 // defines ordering of blocks
117 std::vector<std::string> blockIds;
118 stkMeshDB_->getElementBlockNames(blockIds);
119
120 std::size_t blockIndex=0;
121 for(std::vector<std::string>::const_iterator idItr=blockIds.begin();
122 idItr!=blockIds.end();++idItr,++blockIndex) {
123 std::string blockId = *idItr;
124
125 // grab elements on this block
126 std::vector<stk::mesh::Entity> blockElmts;
127 stkMeshDB_->getMyElements(blockId,blockElmts);
128
129 // concatenate them into element LID lookup table
130 elements_->insert(elements_->end(),blockElmts.begin(),blockElmts.end());
131
132 // build block to LID map
133 elementBlocks_[blockId] = Teuchos::rcp(new std::vector<LocalOrdinal>);
134 for(std::size_t i=0;i<blockElmts.size();i++)
135 elementBlocks_[blockId]->push_back(stkMeshDB_->elementLocalId(blockElmts[i]));
136 }
137
139
140 blockIndex=0;
141 for(std::vector<std::string>::const_iterator idItr=blockIds.begin();
142 idItr!=blockIds.end();++idItr,++blockIndex) {
143 std::string blockId = *idItr;
144
145 // grab elements on this block
146 std::vector<stk::mesh::Entity> blockElmts;
147 stkMeshDB_->getNeighborElements(blockId,blockElmts);
148
149 // concatenate them into element LID lookup table
150 elements_->insert(elements_->end(),blockElmts.begin(),blockElmts.end());
151
152 // build block to LID map
153 neighborElementBlocks_[blockId] = Teuchos::rcp(new std::vector<LocalOrdinal>);
154 for(std::size_t i=0;i<blockElmts.size();i++)
155 neighborElementBlocks_[blockId]->push_back(stkMeshDB_->elementLocalId(blockElmts[i]));
156 }
157
158 // this expensive operation gurantees ordering of local IDs
159 std::sort(elements_->begin(),elements_->end(),LocalIdCompare(stkMeshDB_));
160
161 // allocate space for element LID to Connectivty map
162 // connectivity size
163 elmtLidToConnPtr_->resize(elements_->size(),0);
164 connSizePtr_->resize(elements_->size(),0);
165}
166
167void
169 LocalOrdinal & nodeIdCnt, LocalOrdinal & edgeIdCnt,
170 LocalOrdinal & faceIdCnt, LocalOrdinal & cellIdCnt,
171 GlobalOrdinal & nodeOffset, GlobalOrdinal & edgeOffset,
172 GlobalOrdinal & faceOffset, GlobalOrdinal & cellOffset) const
173{
174 // get the global counts for all the nodes, faces, edges and cells
175 GlobalOrdinal maxNodeId = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank());
176 GlobalOrdinal maxEdgeId = stkMeshDB_->getMaxEntityId(stkMeshDB_->getEdgeRank());
177 GlobalOrdinal maxFaceId = stkMeshDB_->getMaxEntityId(stkMeshDB_->getFaceRank());
178
179 // compute ID counts for each sub cell type
180 int patternDim = fp.getDimension();
181 switch(patternDim) {
182 case 3:
183 faceIdCnt = fp.getSubcellIndices(2,0).size();
184 // Intentional fall-through.
185 case 2:
186 edgeIdCnt = fp.getSubcellIndices(1,0).size();
187 // Intentional fall-through.
188 case 1:
189 nodeIdCnt = fp.getSubcellIndices(0,0).size();
190 cellIdCnt = fp.getSubcellIndices(patternDim,0).size();
191 break;
192 case 0:
193 default:
194 TEUCHOS_ASSERT(false);
195 };
196
197 // compute offsets for each sub cell type
198 nodeOffset = 0;
199 edgeOffset = nodeOffset+(maxNodeId+1)*nodeIdCnt;
200 faceOffset = edgeOffset+(maxEdgeId+1)*edgeIdCnt;
201 cellOffset = faceOffset+(maxFaceId+1)*faceIdCnt;
202
203 // sanity check
204 TEUCHOS_ASSERT(nodeOffset <= edgeOffset
205 && edgeOffset <= faceOffset
206 && faceOffset <= cellOffset);
207}
208
211 unsigned subcellRank,
212 LocalOrdinal idCnt,
213 GlobalOrdinal offset,
214 const unsigned maxIds)
215{
216 if(idCnt<=0)
217 return 0 ;
218
219 // loop over all relations of specified type, unless requested
220 LocalOrdinal numIds = 0;
221 std::vector<GlobalOrdinal>& connectivity = *connectivityPtr_;
222 stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
223 const stk::mesh::EntityRank rank = static_cast<stk::mesh::EntityRank>(subcellRank);
224
225#ifdef PANZER_DEBUG
226 TEUCHOS_TEST_FOR_EXCEPTION(maxIds > bulkData.num_connectivity(element, rank),
227 std::runtime_error,
228 "ERROR: The maxIds (num vertices from basis cell topology) is greater than the num vertices in the stk mesh topology!");
229#endif
230
231 const size_t num_rels = (maxIds > 0) ? maxIds : bulkData.num_connectivity(element, rank);
232 stk::mesh::Entity const* relations = bulkData.begin(element, rank);
233 for(std::size_t sc=0; sc<num_rels; ++sc) {
234 stk::mesh::Entity subcell = relations[sc];
235
236 // add connectivities: adjust for STK indexing craziness
237 for(LocalOrdinal i=0;i<idCnt;i++) {
238 connectivity.push_back(offset+idCnt*(bulkData.identifier(subcell)-1)+i);
239 }
240
241 numIds += idCnt;
242 }
243 return numIds;
244}
245
246void
248 unsigned subcellRank,unsigned subcellId,GlobalOrdinal newId,
249 GlobalOrdinal offset)
250{
251 LocalOrdinal elmtLID = stkMeshDB_->elementLocalId(element);
252 GlobalOrdinal * conn = &(*connectivityPtr_)[(*elmtLidToConnPtr_)[elmtLID]];
253 const std::vector<int> & subCellIndices = fp.getSubcellIndices(subcellRank,subcellId);
254
255 // add connectivities: adjust for STK indexing craziness
256 for(std::size_t i=0;i<subCellIndices.size();i++) {
257 conn[subCellIndices[i]] = offset+subCellIndices.size()*(newId-1)+i;
258 }
259}
260
262{
263 PANZER_FUNC_TIME_MONITOR_DIFF("panzer_stk::STKConnManager::buildConnectivity", build_connectivity);
264
266 auto search = std::find_if(cached_conn_managers_.begin(),
269 if (search != cached_conn_managers_.end()) {
270 PANZER_FUNC_TIME_MONITOR_DIFF("panzer_stk::STKConnManager::copyingCachedConnectivity", copy_cached_connectivity);
271 {
272 STKConnManager& cm = *(search->second);
273 TEUCHOS_ASSERT(cm.stkMeshDB_.get() == stkMeshDB_.get());
274 elements_ = cm.elements_;
285 }
286 return;
287 }
288 }
289
290 stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
291
292 // get element info from STK_Interface
293 // object and build a local element mapping.
295
296 // Bind after buildLocalElementMapping(), which allocates new arrays
297 std::vector<LocalOrdinal>& elmtLidToConn = *elmtLidToConnPtr_;
298 std::vector<LocalOrdinal>& connSize = *connSizePtr_;
299 std::vector<GlobalOrdinal>& connectivity = *connectivityPtr_;
300
301 // Build sub cell ID counts and offsets
302 // ID counts = How many IDs belong on each subcell (number of mesh DOF used)
303 // Offset = What is starting index for subcell ID type?
304 // Global numbering goes like [node ids, edge ids, face ids, cell ids]
305 LocalOrdinal nodeIdCnt=0, edgeIdCnt=0, faceIdCnt=0, cellIdCnt=0;
306 GlobalOrdinal nodeOffset=0, edgeOffset=0, faceOffset=0, cellOffset=0;
307 buildOffsetsAndIdCounts(fp, nodeIdCnt, edgeIdCnt, faceIdCnt, cellIdCnt,
308 nodeOffset, edgeOffset, faceOffset, cellOffset);
309
310 // std::cout << "node: count = " << nodeIdCnt << ", offset = " << nodeOffset << std::endl;
311 // std::cout << "edge: count = " << edgeIdCnt << ", offset = " << edgeOffset << std::endl;
312 // std::cout << "face: count = " << faceIdCnt << ", offset = " << faceOffset << std::endl;
313 // std::cout << "cell: count = " << cellIdCnt << ", offset = " << cellOffset << std::endl;
314
315 // Connectivity only requires lowest order mesh node information
316 // With the notion of extended topologies used by shards, it is
317 // sufficient to take the first num_vertices nodes for connectivity purposes.
318 const unsigned num_vertices = fp.getCellTopology().getVertexCount();
319
320 // loop over elements and build global connectivity
321 for(std::size_t elmtLid=0;elmtLid!=elements_->size();++elmtLid) {
322 GlobalOrdinal numIds = 0;
323 stk::mesh::Entity element = (*elements_)[elmtLid];
324
325 // get index into connectivity array
326 elmtLidToConn[elmtLid] = connectivity.size();
327
328 // add connectivities for sub cells
329 // Second order or higher mesh nodes are only needed downstream by the FE bases
330 // The connection manager only expects first order nodes (vertices), so we subselect if necessary
331 // All edge and face IDs are stored
332 numIds += addSubcellConnectivities(element,stkMeshDB_->getNodeRank(),nodeIdCnt,nodeOffset,num_vertices);
333 numIds += addSubcellConnectivities(element,stkMeshDB_->getEdgeRank(),edgeIdCnt,edgeOffset);
334 numIds += addSubcellConnectivities(element,stkMeshDB_->getFaceRank(),faceIdCnt,faceOffset);
335
336 // add connectivity for parent cells
337 if(cellIdCnt>0) {
338 // add connectivities: adjust for STK indexing craziness
339 for(LocalOrdinal i=0;i<cellIdCnt;i++)
340 connectivity.push_back(cellOffset+cellIdCnt*(bulkData.identifier(element)-1));
341
342 numIds += cellIdCnt;
343 }
344
345 connSize[elmtLid] = numIds;
346 }
347
348 applyPeriodicBCs( fp, nodeOffset, edgeOffset, faceOffset, cellOffset);
349
350 // This method does not modify the connectivity array. But it should be
351 // called here because the data it initializes should be available at the
352 // same time as the connectivity array.
355
357 auto fp_rcp = fp.clone();
358 cached_conn_managers_.push_back(std::make_pair(fp_rcp,Teuchos::rcp(new panzer_stk::STKConnManager(*this))));
359 }
360}
361
363{
364 // walk through the element blocks and figure out which this ID belongs to
365 stk::mesh::Entity element = (*elements_)[localElmtId];
366
367 return stkMeshDB_->containingBlockId(element);
368}
369
371 GlobalOrdinal faceOffset, GlobalOrdinal /* cellOffset */)
372{
373 using Teuchos::RCP;
374 using Teuchos::rcp;
375
376 PANZER_FUNC_TIME_MONITOR_DIFF("panzer_stk::STKConnManager::applyPeriodicBCs", apply_periodic_bcs);
377
378 std::pair<Teuchos::RCP<std::vector<std::pair<std::size_t,std::size_t> > >, Teuchos::RCP<std::vector<unsigned int> > > matchedValues
379 = stkMeshDB_->getPeriodicNodePairing();
380
381 Teuchos::RCP<std::vector<std::pair<std::size_t,std::size_t> > > matchedNodes
382 = matchedValues.first;
383 Teuchos::RCP<std::vector<unsigned int> > matchTypes
384 = matchedValues.second;
385
386 // no matchedNodes means nothing to do!
387 if(matchedNodes==Teuchos::null) return;
388
389 for(std::size_t m=0;m<matchedNodes->size();m++) {
390 stk::mesh::EntityId oldNodeId = (*matchedNodes)[m].first;
391 std::size_t newNodeId = (*matchedNodes)[m].second;
392
393 std::vector<stk::mesh::Entity> elements;
394 std::vector<int> localIds;
395
396 GlobalOrdinal offset0 = 0; // to make numbering consistent with that in PeriodicBC_Matcher
397 GlobalOrdinal offset1 = 0; // offset for dof indexing
398 if((*matchTypes)[m] == 0)
399 offset1 = nodeOffset-offset0;
400 else if((*matchTypes)[m] == 1){
401 offset0 = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank());
402 offset1 = edgeOffset-offset0;
403 } else if((*matchTypes)[m] == 2){
404 offset0 = stkMeshDB_->getMaxEntityId(stkMeshDB_->getNodeRank())+stkMeshDB_->getMaxEntityId(stkMeshDB_->getEdgeRank());
405 offset1 = faceOffset-offset0;
406 } else
407 TEUCHOS_ASSERT(false);
408
409 // get relevent elements and node IDs
410 stkMeshDB_->getOwnedElementsSharingNode(stk::mesh::EntityId(oldNodeId-offset0),elements,localIds,(*matchTypes)[m]);
411
412 // modify global numbering already built for each element
413 for(std::size_t e=0;e<elements.size();e++){
414 modifySubcellConnectivities(fp,elements[e],(*matchTypes)[m],localIds[e],newNodeId,offset1);
415 }
416
417 }
418}
419
422void STKConnManager::getDofCoords(const std::string & blockId,
423 const panzer::Intrepid2FieldPattern & coordProvider,
424 std::vector<std::size_t> & localCellIds,
425 Kokkos::DynRankView<double,PHX::Device> & points) const
426{
427 int dim = coordProvider.getDimension();
428 int numIds = coordProvider.numberIds();
429
430 // grab element nodes
431 Kokkos::DynRankView<double,PHX::Device> nodes;
432 workset_utils::getIdsAndNodes(*stkMeshDB_,blockId,localCellIds,nodes);
433
434 // setup output array
435 points = Kokkos::DynRankView<double,PHX::Device>("points",localCellIds.size(),numIds,dim);
436 coordProvider.getInterpolatoryCoordinates(nodes,points,stkMeshDB_->getCellTopology(blockId));
437}
438
440{
441 return ! sidesetsToAssociate_.empty();
442}
443
444void STKConnManager::associateElementsInSideset(const std::string sideset_id)
445{
446 sidesetsToAssociate_.push_back(sideset_id);
447 sidesetYieldedAssociations_.push_back(false);
448}
449
450inline std::size_t
451getElementIdx(const std::vector<stk::mesh::Entity>& elements,
452 stk::mesh::Entity const e)
453{
454 return static_cast<std::size_t>(
455 std::distance(elements.begin(), std::find(elements.begin(), elements.end(), e)));
456}
457
459{
460 stk::mesh::BulkData& bulkData = *stkMeshDB_->getBulkData();
461 std::vector<std::vector<LocalOrdinal> >& elmtToAssociatedElmts = *elmtToAssociatedElmtsPtr_;
462 elmtToAssociatedElmts.resize(elements_->size());
463 for (std::size_t i = 0; i < sidesetsToAssociate_.size(); ++i) {
464 std::vector<stk::mesh::Entity> sides;
465 stkMeshDB_->getAllSides(sidesetsToAssociate_[i], sides);
466 sidesetYieldedAssociations_[i] = ! sides.empty();
467 for (std::vector<stk::mesh::Entity>::const_iterator si = sides.begin();
468 si != sides.end(); ++si) {
469 stk::mesh::Entity side = *si;
470 const size_t num_elements = bulkData.num_elements(side);
471 stk::mesh::Entity const* elements = bulkData.begin_elements(side);
472 if (num_elements != 2) {
473 // If relations.size() != 2 for one side in the sideset, then it's true
474 // for all, including the first.
475 TEUCHOS_ASSERT(si == sides.begin());
477 break;
478 }
479 const std::size_t ea_id = getElementIdx(*elements_, elements[0]),
480 eb_id = getElementIdx(*elements_, elements[1]);
481 elmtToAssociatedElmts[ea_id].push_back(eb_id);
482 elmtToAssociatedElmts[eb_id].push_back(ea_id);
483 }
484 }
485}
486
487std::vector<std::string> STKConnManager::
488checkAssociateElementsInSidesets(const Teuchos::Comm<int>& comm) const
489{
490 std::vector<std::string> sidesets;
491 for (std::size_t i = 0; i < sidesetYieldedAssociations_.size(); ++i) {
492 int sya, my_sya = sidesetYieldedAssociations_[i] ? 1 : 0;
493 Teuchos::reduceAll(comm, Teuchos::REDUCE_MAX, 1, &my_sya, &sya);
494 if (sya == 0)
495 sidesets.push_back(sidesetsToAssociate_[i]);
496 }
497 return sidesets;
498}
499
500const std::vector<STKConnManager::LocalOrdinal>&
505
506}
virtual int getDimension() const =0
virtual shards::CellTopology getCellTopology() const =0
virtual int numberIds() const
virtual const std::vector< int > & getSubcellIndices(int dim, int cellIndex) const =0
virtual Teuchos::RCP< panzer::FieldPattern > clone() const =0
void getInterpolatoryCoordinates(Kokkos::DynRankView< double, PHX::Device > &coords) const
A panzer::ConnManager implementation backed by an STK mesh, mapping local element IDs to global mesh-...
Teuchos::RCP< std::vector< LocalOrdinal > > elmtLidToConnPtr_
std::vector< std::string > checkAssociateElementsInSidesets(const Teuchos::Comm< int > &comm) const
void applyPeriodicBCs(const panzer::FieldPattern &fp, GlobalOrdinal nodeOffset, GlobalOrdinal edgeOffset, GlobalOrdinal faceOffset, GlobalOrdinal cellOffset)
Teuchos::RCP< std::vector< stk::mesh::Entity > > elements_
virtual Teuchos::RCP< panzer::ConnManager > noConnectivityClone() const
Teuchos::RCP< std::vector< GlobalOrdinal > > connectivityPtr_
std::map< std::string, Teuchos::RCP< std::vector< LocalOrdinal > > > neighborElementBlocks_
panzer::ConnManager::LocalOrdinal LocalOrdinal
Teuchos::RCP< std::vector< LocalOrdinal > > connSizePtr_
virtual void getDofCoords(const std::string &blockId, const panzer::Intrepid2FieldPattern &coordProvider, std::vector< std::size_t > &localCellIds, Kokkos::DynRankView< double, PHX::Device > &points) const
void buildOffsetsAndIdCounts(const panzer::FieldPattern &fp, LocalOrdinal &nodeIdCnt, LocalOrdinal &edgeIdCnt, LocalOrdinal &faceIdCnt, LocalOrdinal &cellIdCnt, GlobalOrdinal &nodeOffset, GlobalOrdinal &edgeOffset, GlobalOrdinal &faceOffset, GlobalOrdinal &cellOffset) const
STKConnManager(const Teuchos::RCP< const STK_Interface > &stkMeshDB)
Construct from the STK mesh to build connectivity from. buildConnectivity() must be called before con...
panzer::ConnManager::GlobalOrdinal GlobalOrdinal
virtual void buildConnectivity(const panzer::FieldPattern &fp)
std::vector< bool > sidesetYieldedAssociations_
static std::vector< CachedEntry > cached_conn_managers_
virtual bool hasAssociatedNeighbors() const
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...
std::vector< std::string > sidesetsToAssociate_
virtual const std::vector< LocalOrdinal > & getAssociatedNeighbors(const LocalOrdinal &el) const
std::map< std::string, Teuchos::RCP< std::vector< LocalOrdinal > > > elementBlocks_
Teuchos::RCP< const STK_Interface > stkMeshDB_
std::pair< Teuchos::RCP< const panzer::FieldPattern >, Teuchos::RCP< panzer_stk::STKConnManager > > CachedEntry
virtual std::string getBlockId(LocalOrdinal localElmtId) const
Teuchos::RCP< std::vector< std::vector< LocalOrdinal > > > elmtToAssociatedElmtsPtr_
void associateElementsInSideset(const std::string sideset_id)
static void clearCachedConnectivityData()
If you enable caching with cacheConnectivity(), this must be called prior to exiting the code.
void modifySubcellConnectivities(const panzer::FieldPattern &fp, stk::mesh::Entity element, unsigned subcellRank, unsigned subcellId, GlobalOrdinal newId, GlobalOrdinal offset)
void getIdsAndNodes(const panzer_stk::STK_Interface &mesh, std::string blockId, std::vector< std::size_t > &localIds, ArrayT &nodes)
std::size_t getElementIdx(const std::vector< stk::mesh::Entity > &elements, stk::mesh::Entity const e)
Matches a cache entry on mesh, field pattern and sideset association list.