Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_STK_PeriodicBC_Search.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 <stk_mesh/base/GetEntities.hpp>
14 #include <stk_mesh/base/GetBuckets.hpp>
15 #include <stk_mesh/base/FieldBase.hpp>
16 
17 #include "Panzer_NodeType.hpp"
18 #include "Tpetra_Map.hpp"
19 #include "Tpetra_Import.hpp"
20 #include "Tpetra_Vector.hpp"
21 
22 #include "Teuchos_FancyOStream.hpp"
23 
24 #ifdef PANZER_HAVE_STKSEARCH
25 namespace panzer_stk {
26 
27 namespace periodic_helpers {
28 
29 void fillLocalSearchVector(const STK_Interface & mesh, SphereIdVector & searchVector, const double & error,
30  const std::string & sideName, const std::string & type_, const bool & getGhostedIDs)
31 {
32 
33  // empty optional arguments for real call below
34  // this is partially for backwards compatability but also recognizes that for the first
35  // pairing, these vectors are not needed
36  // they are also not used for side B in every case
37 
38  std::vector<std::string> matchedSides;
39  std::vector<SearchId> potentialIDsToRemap;
40 
41  fillLocalSearchVector(mesh,searchVector,error,sideName,type_,getGhostedIDs,matchedSides,potentialIDsToRemap);
42 
43  return;
44 
45 }
46 
47 void fillLocalSearchVector(const STK_Interface & mesh, SphereIdVector & searchVector, const double & error,
48  const std::string & sideName, const std::string & type_, const bool & getGhostedIDs,
49  const std::vector<std::string> & matchedSides, std::vector<SearchId> & potentialIDsToRemap)
50 {
51  unsigned physicalDim = mesh.getDimension();
52 
53  Teuchos::RCP<stk::mesh::MetaData> metaData = mesh.getMetaData();
54  Teuchos::RCP<stk::mesh::BulkData> bulkData = mesh.getBulkData();
55 
56  const unsigned parallelRank = bulkData->parallel_rank();
57 
58  // grab entities owned by requested side
60  std::stringstream ss;
61  ss << "Can't find a sideset named \"" << sideName << "\" in the mesh" << std::endl;
62  stk::mesh::Part * side = metaData->get_part(sideName,ss.str().c_str());
63 
64  // if ghosted IDs are requested, add in the shared portion
65  stk::mesh::Selector mySides = getGhostedIDs ?
66  (*side) & (metaData->locally_owned_part() | metaData->globally_shared_part()) :
67  (*side) & metaData->locally_owned_part();
68 
69  stk::mesh::EntityRank rank;
71  // the sorting further downstream only uses ids which are offset
72  // based on the entity type
73  stk::mesh::EntityId offset = 0;
74  if(type_ == "coord"){
75  rank = mesh.getNodeRank();
76  field = & mesh.getCoordinatesField();
77  // no offset
78  } else if(type_ == "edge"){
79  rank = mesh.getEdgeRank();
80  field = & mesh.getEdgesField();
81  offset = mesh.getMaxEntityId(mesh.getNodeRank());
82  } else if(type_ == "face"){
83  rank = mesh.getFaceRank();
84  field = & mesh.getFacesField();
85  offset = mesh.getMaxEntityId(mesh.getNodeRank())+mesh.getMaxEntityId(mesh.getEdgeRank());
86  } else {
87  ss << "Can't do BCs of type " << type_ << std::endl;
88  TEUCHOS_TEST_FOR_EXCEPTION(true,std::runtime_error, ss.str())
89  }
90 
91  // remove previously matched nodes
92 
93  stk::mesh::Selector intersection; // empty set to start
94 
95  if (matchedSides.size()>0) {
96  for (size_t j=0; j<matchedSides.size(); ++j) {
97  auto previouslyMatched = matchedSides[j];
98  // add in the overlap between the requested side and the previously matched side
99  intersection = intersection | (mySides & *(metaData->get_part(previouslyMatched)));
100  }
101  // remove all overlaps
102  mySides = mySides - intersection;
103  }
104 
105  // get buckets
106  std::vector<stk::mesh::Bucket*> const& entityBuckets =
107  bulkData->get_buckets(rank, mySides);
108 
109  // loop over entity buckets
110 
111  for(size_t b=0;b<entityBuckets.size();b++) {
112  stk::mesh::Bucket & bucket = *entityBuckets[b];
113  double const* array = stk::mesh::field_data(*field, bucket);
114 
115  // loop over entities
116  for(size_t n=0;n<bucket.size();n++) {
117 
118  double coord[3]; // coordinates
119  // copy coordinates into multi vector
120  for(size_t d=0;d<physicalDim;d++)
121  coord[d] = array[physicalDim*n + d];
122 
123  // need to ensure that higher dimensions are properly zeroed
124  // required for 1D periodic boundary conditions
125  for(size_t d=physicalDim;d<3;d++)
126  coord[d] = 0;
127 
128  // add to the coordinate and id to the search vector
129  // a tolerance can be specified
130  // TODO allow for relative tolerances...
131  stk::search::Point<double> center(coord[0],coord[1],coord[2]);
132  stk::mesh::EntityKey trueKey = bulkData->entity_key(bucket[n]);
133  stk::mesh::EntityKey shiftedKey(trueKey.rank(), trueKey.id()+offset);
134  SearchId search_id(shiftedKey, parallelRank);
135 
136  searchVector.emplace_back( Sphere(center, error), search_id);
137  }
138  }
139 
140  // for multiperiodic case, populate the potentialIDsToRemap vector with the IDs that have
141  // already been matched and fall on this side
142 
143  if (matchedSides.size()>0) {
144  TEUCHOS_ASSERT(potentialIDsToRemap.size()==0);
145  // reset mySides
146  mySides = getGhostedIDs ?
147  (*side) & (metaData->locally_owned_part() | metaData->globally_shared_part()) :
148  (*side) & metaData->locally_owned_part();
149 
150  std::vector<stk::mesh::Bucket*> const & intersectionEntityBuckets =
151  bulkData->get_buckets(rank, mySides & intersection);
152 
153  // loop over entity buckets
154 
155  for(size_t b=0;b<intersectionEntityBuckets.size();b++) {
156  stk::mesh::Bucket & bucket = *intersectionEntityBuckets[b];
157  // loop over entities
158  for(size_t n=0;n<bucket.size();n++) {
159  stk::mesh::EntityKey trueKey = bulkData->entity_key(bucket[n]);
160  stk::mesh::EntityKey shiftedKey(trueKey.rank(), trueKey.id()+offset);
161  potentialIDsToRemap.emplace_back(shiftedKey, parallelRank);
162  }
163  }
164  }
165 
166  return;
167 }
168 
169 const std::vector<double> computeGlobalCentroid(const STK_Interface & mesh, const std::string & sideName)
170 {
171  // TODO too much replicated code here
172  unsigned physicalDim = mesh.getDimension();
173 
174  Teuchos::RCP<stk::mesh::MetaData> metaData = mesh.getMetaData();
175  Teuchos::RCP<stk::mesh::BulkData> bulkData = mesh.getBulkData();
176 
177  // grab requested side
179  std::stringstream ss;
180  ss << "Can't find part=\"" << sideName << "\"" << std::endl;
181  stk::mesh::Part * side = metaData->get_part(sideName,ss.str().c_str());
182  stk::mesh::Selector mySides = (*side) & metaData->locally_owned_part();
183 
184  // get node buckets
185  std::vector<stk::mesh::Bucket*> const& entityBuckets =
186  bulkData->get_buckets(mesh.getNodeRank(), mySides);
187 
188  // loop over node buckets
189  double localCentroid[3] = {0.,0.,0.};
190  int localNodeCount = 0;
191  for(size_t b=0;b<entityBuckets.size();b++) {
192  stk::mesh::Bucket & bucket = *entityBuckets[b];
193  double const* array = stk::mesh::field_data(mesh.getCoordinatesField(), bucket);
194 
195  // loop over nodes
196  for(size_t n=0;n<bucket.size();n++) {
197 
198  ++localNodeCount;
199  // sum (note that unused dimensions are skipped)
200  for(size_t d=0;d<physicalDim;d++)
201  localCentroid[d] += array[physicalDim*n + d];
202 
203  }
204  }
205  int globalNodeCount = 0;
206 
207  auto comm = mesh.getComm();
208 
209  double globalCentroid[3] = { };
210 
211  Teuchos::reduceAll(*comm,Teuchos::REDUCE_SUM,1,&localNodeCount,&globalNodeCount);
212  Teuchos::reduceAll(*comm,Teuchos::REDUCE_SUM,3,&localCentroid[0],&globalCentroid[0]);
213 
214  std::vector<double> result = {0.,0.,0.};
215  for (size_t d=0;d<physicalDim;d++)
216  result[d] = globalCentroid[d]/globalNodeCount;
217 
218  return result;
219 }
220 
221 void updateMapping(Teuchos::RCP<std::vector<std::pair<size_t,size_t> > > & currentMatches,
222  const std::vector<std::pair<size_t,size_t> > & previousMatches,
223  const std::vector<SearchId> & IDsToRemap, const STK_Interface & mesh)
224 {
225 
226  using LO = panzer::LocalOrdinal;
227  using GO = panzer::GlobalOrdinal;
229  using Map = Tpetra::Map<LO,GO,NODE>;
230  using Importer = Tpetra::Import<LO,GO,NODE>;
231 
232  auto comm = mesh.getComm();
233 
234  // store maps
235  // this is necessary because of the uniqueness requirements
236  // and convenient to update the map
237 
238  std::map<size_t,size_t> myPreviousAtoB,myCurrentAtoB;
239  std::map<size_t,std::vector<size_t> > myPreviousBtoA;
240  for (size_t i=0;i<previousMatches.size();++i) {
241  myPreviousAtoB[previousMatches[i].first] = previousMatches[i].second;
242  // may not be one-to-one
243  myPreviousBtoA[previousMatches[i].second].push_back(previousMatches[i].first);
244  }
245  for (size_t i=0;i<currentMatches->size();++i)
246  myCurrentAtoB[(*currentMatches)[i].first] = (*currentMatches)[i].second;
247 
248  // find which IDs we need to query to get THEIR A to B map
249  // this means we need to the the B id of our previous match for the IDsToRemap
250  std::vector<GO> requestedAIDs;
251 
252  for (auto & id : IDsToRemap)
253  requestedAIDs.push_back(myPreviousAtoB[id.id().id()]);
254 
255  // quick and dirty way to get rid of repeated entries on each process
256  std::set<GO> uniqueAIDs(requestedAIDs.begin(),requestedAIDs.end());
257  requestedAIDs = std::vector<GO>(uniqueAIDs.begin(),uniqueAIDs.end());
258 
259  // find which A ids we have in our new mapping
260  std::vector<GO> newAIDs(currentMatches->size());
261 
262  for (size_t i=0;i<currentMatches->size();++i) {
263  newAIDs[i] = (*currentMatches)[i].first;
264  }
265 
266  // create teuchos maps
268  Teuchos::RCP<const Map> testMap = Teuchos::rcp(new Map(computeInternally,&newAIDs[0],newAIDs.size(),0,comm));
269  Teuchos::RCP<const Map> newAIDsMap;
270  // source must be unique across communicator
271  if (!testMap->isOneToOne()){
272  newAIDsMap = Tpetra::createOneToOne<LO,GO,NODE>(testMap);
273  } else {
274  newAIDsMap = testMap;
275  }
276 
277  Teuchos::RCP<Map> requestedAIDsMap = Teuchos::rcp(new Map(computeInternally,&requestedAIDs[0],requestedAIDs.size(),0,comm));
278 
279  Importer importer(newAIDsMap,requestedAIDsMap);
280 
281  // send out my A to B map
282  Tpetra::Vector<GO,LO,GO,NODE> newBIDs(newAIDsMap);
283  auto newBIDsHost = newBIDs.getLocalViewHost(Tpetra::Access::OverwriteAll);
284  auto myGIDs = newAIDsMap->getMyGlobalIndices();
285  for (size_t i=0;i<myGIDs.size();++i)
286  newBIDsHost(i,0) = myCurrentAtoB[myGIDs[i]];
287 
288  Tpetra::Vector<GO,LO,GO,NODE> requestedBIDs(requestedAIDsMap);
289  requestedBIDs.doImport(newBIDs,importer,Tpetra::INSERT);
290  auto requestedBIDsHost = requestedBIDs.getLocalViewHost(Tpetra::Access::ReadOnly);
291 
292  // now overwrite previous map where necessary...
293  // what about error checking? what is the default is something is requested but not there?
294  // TODO this assumes that teuchos maps and communication does not
295  // alter the ordering in anyway so that AIDs and IDsToRemap correspond appropriately
296  size_t ind = 0;
297  for (const auto & id : requestedAIDs) {
298  // get the corresponding ids to update in the previous map
299  for (const auto & idToUpdate : myPreviousBtoA[id])
300  // update with the final B id
301  myPreviousAtoB[idToUpdate] = requestedBIDsHost(ind,0);
302  ++ind;
303  }
304 
305  // and add to new map...
306  // needs to respect the previous ordering or type_vec in getPeriodicNodePairing will be wrong
307  for (const auto & AB : previousMatches) {
308  // so we get the A ids in order
309  auto id = AB.first;
310  // and use the updated previous A to B map
311  (*currentMatches).emplace_back(std::pair<size_t,size_t>(id,myPreviousAtoB[id]));
312  }
313 
314  return;
315 }
316 
317 void appendMapping(Teuchos::RCP<std::vector<std::pair<size_t,size_t> > > & currentMatches,
318  const std::vector<std::pair<size_t,size_t> > & previousMatches)
319 {
320  // add previous mapping to new map
321  for (const auto & AB : previousMatches)
322  (*currentMatches).push_back(AB);
323 
324  return;
325 }
326 
327 } // end periodic_helpers
328 
329 } // end panzer_stk
330 #endif
stk::mesh::Field< double > VectorFieldType
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
PHX::MDField< ScalarT, panzer::Cell, panzer::IP > result
A field that will be used to build up the result of the integral we&#39;re performing.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
PHX::MDField< ScalarT, panzer::Cell, panzer::BASIS > field
A field to which we&#39;ll contribute, or in which we&#39;ll store, the result of computing this integral...
#define TEUCHOS_ASSERT(assertion_test)
Tpetra::KokkosCompat::KokkosDeviceWrapperNode< PHX::Device > TpetraNodeType