Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_DOFManager.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 
43 #ifndef PANZER_DOF_MANAGER2_IMPL_HPP
44 #define PANZER_DOF_MANAGER2_IMPL_HPP
45 
46 #include <map>
47 #include <set>
48 
49 #include <mpi.h>
50 
51 #include "PanzerDofMgr_config.hpp"
52 #include "Panzer_FieldPattern.hpp"
55 #include "Panzer_ConnManager.hpp"
57 #include "Panzer_DOFManager.hpp"
61 
62 #include "Teuchos_RCP.hpp"
63 #include "Teuchos_Array.hpp"
64 #include "Teuchos_ArrayView.hpp"
65 
66 #include "Tpetra_Map.hpp"
67 #include "Tpetra_Export.hpp"
68 #include "Tpetra_Vector.hpp"
69 #include "Tpetra_MultiVector.hpp"
70 
71 #include <unordered_set> // a hash table
72 
73 /*
74 #define HAVE_ZOLTAN2
75 #ifdef HAVE_ZOLTAN2
76 #include "Zoltan2_XpetraCrsGraphInput.hpp"
77 #include "Zoltan2_OrderingProblem.hpp"
78 #endif
79 */
80 
81 namespace panzer {
82 
84 namespace {
85 template <typename LocalOrdinal,typename GlobalOrdinal>
86 class HashTieBreak : public Tpetra::Details::TieBreak<LocalOrdinal,GlobalOrdinal> {
87  const unsigned int seed_;
88 
89 public:
90  HashTieBreak(const unsigned int seed = (2654435761U))
91  : seed_(seed) { }
92 
93  virtual std::size_t selectedIndex(GlobalOrdinal GID,
94  const std::vector<std::pair<int,LocalOrdinal> > & pid_and_lid) const
95  {
96  // this is Epetra's hash/Tpetra's default hash: See Tpetra HashTable
97  int intkey = (int) ((GID & 0x000000007fffffffLL) +
98  ((GID & 0x7fffffff80000000LL) >> 31));
99  return std::size_t((seed_ ^ intkey) % pid_and_lid.size());
100  }
101 };
102 
103 }
104 
106 namespace {
107 template <typename LocalOrdinal,typename GlobalOrdinal>
108 class GreedyTieBreak : public Tpetra::Details::TieBreak<LocalOrdinal,GlobalOrdinal> {
109 
110 public:
111  GreedyTieBreak() { }
112 
113  virtual bool mayHaveSideEffects() const {
114  return true;
115  }
116 
117  virtual std::size_t selectedIndex(GlobalOrdinal /* GID */,
118  const std::vector<std::pair<int,LocalOrdinal> > & pid_and_lid) const
119  {
120  // always choose index of pair with smallest pid
121  const std::size_t numLids = pid_and_lid.size();
122  std::size_t idx = 0;
123  int minpid = pid_and_lid[0].first;
124  std::size_t minidx = 0;
125  for (idx = 0; idx < numLids; ++idx) {
126  if (pid_and_lid[idx].first < minpid) {
127  minpid = pid_and_lid[idx].first;
128  minidx = idx;
129  }
130  }
131  return minidx;
132  }
133 };
134 
135 }
136 
140 
141 using Teuchos::RCP;
142 using Teuchos::rcp;
143 using Teuchos::ArrayRCP;
144 using Teuchos::Array;
145 using Teuchos::ArrayView;
146 
149  : numFields_(0),buildConnectivityRun_(false),requireOrientations_(false), useTieBreak_(false), useNeighbors_(false)
150 { }
151 
153 DOFManager::DOFManager(const Teuchos::RCP<ConnManager> & connMngr,MPI_Comm mpiComm)
154  : numFields_(0),buildConnectivityRun_(false),requireOrientations_(false), useTieBreak_(false), useNeighbors_(false)
155 {
156  setConnManager(connMngr,mpiComm);
157 }
158 
160 void DOFManager::setConnManager(const Teuchos::RCP<ConnManager> & connMngr, MPI_Comm mpiComm)
161 {
163  "DOFManager::setConnManager: setConnManager cannot be called after "
164  "buildGlobalUnknowns has been called");
165  connMngr_ = connMngr;
166  //We acquire the block ordering from the connmanager.
167  connMngr_->getElementBlockIds(blockOrder_);
168  for (size_t i = 0; i < blockOrder_.size(); ++i) {
169  blockNameToID_.insert(std::map<std::string,int>::value_type(blockOrder_[i],i));
170  //We must also initialize vectors for FP associations.
171  }
172  blockToAssociatedFP_.resize(blockOrder_.size());
173  communicator_ = Teuchos::rcp(new Teuchos::MpiComm<int>(Teuchos::opaqueWrapper(mpiComm)));
174 }
175 
177 //Adds a field to be used in creating the Global Numbering
178 //Returns the index for the field pattern
179 int DOFManager::addField(const std::string & str, const Teuchos::RCP<const FieldPattern> & pattern,
180  const panzer::FieldType& type)
181 {
183  "DOFManager::addField: addField cannot be called after "
184  "buildGlobalUnknowns has been called");
185 
186  fieldPatterns_.push_back(pattern);
187  fieldTypes_.push_back(type);
188  fieldNameToAID_.insert(std::map<std::string,int>::value_type(str, numFields_));
189 
190  //The default values for IDs are the sequential order they are added in.
191  fieldStringOrder_.push_back(str);
192  fieldAIDOrder_.push_back(numFields_);
193 
194  for(std::size_t i=0;i<blockOrder_.size();i++) {
195  blockToAssociatedFP_[i].push_back(numFields_);
196  }
197 
198  ++numFields_;
199  return numFields_-1;
200 }
201 
203 int DOFManager::addField(const std::string & blockID, const std::string & str, const Teuchos::RCP<const FieldPattern> & pattern,
204  const panzer::FieldType& type)
205 {
207  "DOFManager::addField: addField cannot be called after "
208  "buildGlobalUnknowns has been called");
209  TEUCHOS_TEST_FOR_EXCEPTION((connMngr_==Teuchos::null),std::logic_error,
210  "DOFManager::addField: you must add a ConnManager before"
211  "you can associate a FP with a given block.")
212  bool found=false;
213  size_t blocknum=0;
214  while(!found && blocknum<blockOrder_.size()){
215  if(blockOrder_[blocknum]==blockID){
216  found=true;
217  break;
218  }
219  blocknum++;
220  }
221  TEUCHOS_TEST_FOR_EXCEPTION(!found,std::logic_error, "DOFManager::addField: Invalid block name.");
222 
223  //This will be different if the FieldPattern is already present.
224  //We need to check for that.
225  found=false;
226  std::map<std::string,int>::const_iterator fpIter = fieldNameToAID_.find(str);
227  if(fpIter!=fieldNameToAID_.end())
228  found=true;
229 
230  if(!found){
231  fieldPatterns_.push_back(pattern);
232  fieldTypes_.push_back(type);
233  fieldNameToAID_.insert(std::map<std::string,int>::value_type(str, numFields_));
234  //The default values for IDs are the sequential order they are added in.
235  fieldStringOrder_.push_back(str);
236  fieldAIDOrder_.push_back(numFields_);
237 
238  //This is going to be associated with blocknum.
239  blockToAssociatedFP_[blocknum].push_back(numFields_);
240  ++numFields_;
241  return numFields_-1;
242  }
243  else{
244  blockToAssociatedFP_[blocknum].push_back(fpIter->second);
245  return numFields_;
246  }
247 }
248 
251 {
252  std::map<std::string,int>::const_iterator fitr = fieldNameToAID_.find(name);
253  if(fitr==fieldNameToAID_.end())
254  return Teuchos::null;
255 
256  if(fitr->second<int(fieldPatterns_.size()))
257  return fieldPatterns_[fitr->second];
258 
259  return Teuchos::null;
260 }
261 
263 Teuchos::RCP<const FieldPattern> DOFManager::getFieldPattern(const std::string & blockId, const std::string & fieldName) const
264 {
265  std::map<std::string,int>::const_iterator fitr = fieldNameToAID_.find(fieldName);
266  if(fitr==fieldNameToAID_.end())
267  return Teuchos::null;
268 
269  bool found=false;
270  size_t blocknum=0;
271  while(!found && blocknum<blockOrder_.size()){
272  if(blockOrder_[blocknum]==blockId){
273  found=true;
274  break;
275  }
276  blocknum++;
277  }
278 
279  if(!found)
280  return Teuchos::null;
281 
282  std::vector<int>::const_iterator itr = std::find(blockToAssociatedFP_[blocknum].begin(),
283  blockToAssociatedFP_[blocknum].end(),fitr->second);
284  if(itr!=blockToAssociatedFP_[blocknum].end()) {
285  if(fitr->second<int(fieldPatterns_.size()))
286  return fieldPatterns_[fitr->second];
287  }
288 
289  return Teuchos::null;
290 }
291 
293 void DOFManager::getOwnedIndices(std::vector<panzer::GlobalOrdinal>& indices) const
294 {
295  indices = owned_;
296 }
297 
299 void DOFManager::getGhostedIndices(std::vector<panzer::GlobalOrdinal>& indices) const
300 {
301  indices = ghosted_;
302 }
303 
305 void DOFManager::getOwnedAndGhostedIndices(std::vector<panzer::GlobalOrdinal>& indices) const
306 {
307  using std::size_t;
308  indices.resize(owned_.size() + ghosted_.size());
309  for (size_t i(0); i < owned_.size(); ++i)
310  indices[i] = owned_[i];
311  for (size_t i(0); i < ghosted_.size(); ++i)
312  indices[owned_.size() + i] = ghosted_[i];
313 }
314 
316 void DOFManager::getElementGIDsAsInt(panzer::LocalOrdinal localElementID, std::vector<int>& gids, const std::string& /* blockIdHint */) const
317 {
318  const auto & element_ids = elementGIDs_[localElementID];
319  gids.resize(element_ids.size());
320  for (std::size_t i=0; i < gids.size(); ++i)
321  gids[i] = element_ids[i];
322 }
323 
325 void DOFManager::getOwnedIndicesAsInt(std::vector<int>& indices) const
326 {
327  indices.resize(owned_.size());
328  for (std::size_t i=0; i < owned_.size(); ++i)
329  indices[i] = owned_[i];
330 }
331 
333 void DOFManager::getGhostedIndicesAsInt(std::vector<int>& indices) const
334 {
335  indices.resize(ghosted_.size());
336  for (std::size_t i=0; i < ghosted_.size(); ++i)
337  indices[i] = ghosted_[i];
338 }
339 
341 void DOFManager::getOwnedAndGhostedIndicesAsInt(std::vector<int>& indices) const
342 {
343  indices.resize(owned_.size() + ghosted_.size());
344  for (std::size_t i=0; i < owned_.size(); ++i)
345  indices[i] = owned_[i];
346  for (std::size_t i=0; i < ghosted_.size(); ++i)
347  indices[owned_.size() + i] = ghosted_[i];
348 }
349 
352 {
353  return owned_.size();
354 }
355 
358 {
359  return ghosted_.size();
360 }
361 
364 {
365  return owned_.size() + ghosted_.size();
366 }
367 
370 {
371  return numFields_;
372 }
373 
375 const std::vector<int> &
376 DOFManager::getGIDFieldOffsets(const std::string & blockID, int fieldNum) const
377 {
378  TEUCHOS_TEST_FOR_EXCEPTION(!buildConnectivityRun_,std::logic_error, "DOFManager::getGIDFieldOffsets: cannot be called before "
379  "buildGlobalUnknowns has been called");
380  std::map<std::string,int>::const_iterator bitr = blockNameToID_.find(blockID);
381  if(bitr==blockNameToID_.end())
382  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"DOFManager::fieldInBlock: invalid block name");
383  int bid=bitr->second;
384  if(fa_fps_[bid]!=Teuchos::null)
385  return fa_fps_[bid]->localOffsets(fieldNum);
386 
387  static const std::vector<int> empty;
388  return empty;
389 }
390 
392 const PHX::View<const int*>
393 DOFManager::getGIDFieldOffsetsKokkos(const std::string & blockID, int fieldNum) const
394 {
395  TEUCHOS_TEST_FOR_EXCEPTION(!buildConnectivityRun_,std::logic_error, "DOFManager::getGIDFieldOffsets: cannot be called before "
396  "buildGlobalUnknowns has been called");
397  std::map<std::string,int>::const_iterator bitr = blockNameToID_.find(blockID);
398  if(bitr==blockNameToID_.end()) {
399  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"DOFManager::fieldInBlock: invalid block name");
400  }
401 
402  int bid=bitr->second;
403  if(fa_fps_[bid]!=Teuchos::null)
404  return fa_fps_[bid]->localOffsetsKokkos(fieldNum);
405 
406  static const PHX::View<int*> empty("panzer::DOFManager::getGIDFieldOffsetsKokkos() empty",0);
407  return empty;
408 }
409 
412 DOFManager::getGIDFieldOffsetsKokkos(const std::string & blockID, const std::vector<int> & fieldNums) const
413 {
414  TEUCHOS_TEST_FOR_EXCEPTION(!buildConnectivityRun_,std::logic_error, "DOFManager::getGIDFieldOffsets: cannot be called before "
415  "buildGlobalUnknowns has been called");
416  std::map<std::string,int>::const_iterator bitr = blockNameToID_.find(blockID);
417  if(bitr==blockNameToID_.end()) {
418  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"DOFManager::fieldInBlock: invalid block name");
419  }
420 
421  PHX::ViewOfViews3<1,PHX::View<const int*>> vov("panzer::getGIDFieldOffsetsKokkos vector version",fieldNums.size());
422  vov.disableSafetyCheck(); // Its going to be moved/copied
423 
424  int bid=bitr->second;
425 
426  for (size_t i=0; i < fieldNums.size(); ++i) {
427  if(fa_fps_[bid]!=Teuchos::null) {
428  vov.addView(fa_fps_[bid]->localOffsetsKokkos(fieldNums[i]),i);
429  }
430  else {
431  TEUCHOS_TEST_FOR_EXCEPTION(true,std::runtime_error,"panzer::DOFManager::getGIDFieldOffsets() - no field pattern exists in block "
432  << blockID << "for field number " << fieldNums[i] << " exists!");
433  // vov.addView(PHX::View<int*>("panzer::DOFManager::getGIDFieldOffsetsKokkos() empty",0),i);
434  }
435  }
436 
437  vov.syncHostToDevice();
438 
439  return vov;
440 }
441 
443 void DOFManager::getElementGIDs(panzer::LocalOrdinal localElementID, std::vector<panzer::GlobalOrdinal>& gids, const std::string& /* blockIdHint */) const
444 {
445  gids = elementGIDs_[localElementID];
446 }
447 
450 {
451  /* STEPS.
452  * 1. Build GA_FP and all block's FA_FP's and place into respective data structures.
453  */
455  fieldPatterns_.push_back(Teuchos::rcp(new NodalFieldPattern(fieldPatterns_[0]->getCellTopology())));
456  fieldTypes_.push_back(FieldType::CG);
457  }
458 
459  TEUCHOS_ASSERT(fieldPatterns_.size() == fieldTypes_.size());
460  std::vector<std::pair<FieldType,Teuchos::RCP<const FieldPattern>>> tmp;
461  for (std::size_t i=0; i < fieldPatterns_.size(); ++i)
462  tmp.push_back(std::make_pair(fieldTypes_[i],fieldPatterns_[i]));
463 
465 
466  connMngr_->buildConnectivity(*aggFieldPattern);
467 
468  // using new geometric pattern, build global unknowns
469  this->buildGlobalUnknowns(aggFieldPattern);
470 }
471 
474 {
475  // some typedefs
476  typedef panzer::TpetraNodeType Node;
477  typedef Tpetra::Map<panzer::LocalOrdinal, panzer::GlobalOrdinal, Node> Map;
478 
479  typedef Tpetra::Import<panzer::LocalOrdinal,panzer::GlobalOrdinal,Node> Import;
480 
481  //the GIDs are of type panzer::GlobalOrdinal.
482  typedef Tpetra::MultiVector<panzer::GlobalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,Node> MultiVector;
483 
484  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns",buildGlobalUnknowns);
485 
486  Teuchos::FancyOStream out(Teuchos::rcpFromRef(std::cout));
487  out.setOutputToRootOnly(-1);
488  out.setShowProcRank(true);
489 
491  "DOFManager::buildGlobalUnknowns: buildGlobalUnknowns cannot be called again "
492  "after buildGlobalUnknowns has been called");
493 
494  // this is a safety check to make sure that nodes are included
495  // in the geometric field pattern when orientations are required
497  std::size_t sz = geomPattern->getSubcellIndices(0,0).size();
498 
499  TEUCHOS_TEST_FOR_EXCEPTION(sz==0,std::logic_error,
500  "DOFManager::buildGlobalUnknowns requires a geometric pattern including "
501  "the nodes when orientations are needed!");
502  }
503 
504  /* STEPS.
505  * 1. Build all block's FA_FP's and place into respective data structures.
506  */
507  ga_fp_ = geomPattern;
508 
509  // given a set of elements over each element block build an overlap
510  // map that will provide the required element entities for the
511  // set of elements requested.
512  ElementBlockAccess ownedAccess(true,connMngr_);
513 
514  // INPUT: To the algorithm in the GUN paper
515  RCP<MultiVector> tagged_overlap_mv = this->buildTaggedMultiVector(ownedAccess);
516  RCP<const Map> overlap_map = tagged_overlap_mv->getMap();
517 
518  RCP<MultiVector> overlap_mv = Tpetra::createMultiVector<panzer::GlobalOrdinal>(overlap_map,(size_t)numFields_);
519 
520  // call the GUN paper algorithm
521  auto non_overlap_pair = this->buildGlobalUnknowns_GUN(*tagged_overlap_mv,*overlap_mv);
522  RCP<MultiVector> non_overlap_mv = non_overlap_pair.first;
523  RCP<MultiVector> tagged_non_overlap_mv = non_overlap_pair.second;
524  RCP<const Map> non_overlap_map = non_overlap_mv->getMap();
525 
526  /* 14. Cross reference local element connectivity and overlap map to
527  * create final GID vectors.
528  */
529 
530  // this bit of code takes the uniquely assigned GIDs and spreads them
531  // out for processing by local element ID
532  this->fillGIDsFromOverlappedMV(ownedAccess,elementGIDs_,*overlap_map,*overlap_mv);
533 
534  // if neighbor unknowns are required, then make sure they are included
535  // in the elementGIDs_
536  if (useNeighbors_) { // enabling this turns on GID construction for
537  // neighbor processors
538  ElementBlockAccess neighborAccess(false,connMngr_);
539  RCP<const Map> overlap_map_neighbor =
540  this->buildOverlapMapFromElements(neighborAccess);
541 
542  // Export e(overlap_map_neighbor,non_overlap_map);
543  Import imp_neighbor(non_overlap_map,overlap_map_neighbor);
544 
545  Teuchos::RCP<MultiVector> overlap_mv_neighbor =
546  Tpetra::createMultiVector<panzer::GlobalOrdinal>(overlap_map_neighbor, (size_t)numFields_);
547 
548  // get all neighbor information
549  overlap_mv_neighbor->doImport(*non_overlap_mv, imp_neighbor,
550  Tpetra::REPLACE);
551 
552  this->fillGIDsFromOverlappedMV(neighborAccess, elementGIDs_,
553  *overlap_map_neighbor, *overlap_mv_neighbor);
554  }
555 
557  // this is where the code is modified to artificially induce GIDs
558  // over 2 Billion unknowns
560  #if 0
561  {
562  panzer::GlobalOrdinal offset = 0xFFFFFFFFLL;
563 
564  for (size_t b = 0; b < blockOrder_.size(); ++b) {
565  const std::vector<panzer::LocalOrdinal> & myElements = connMngr_->getElementBlock(blockOrder_[b]);
566  for (std::size_t l = 0; l < myElements.size(); ++l) {
567  std::vector<panzer::GlobalOrdinal> & localGIDs = elementGIDs_[myElements[l]];
568  for(std::size_t c=0;c<localGIDs.size();c++)
569  localGIDs[c] += offset;
570  }
571  }
572 
573  Teuchos::ArrayRCP<panzer::GlobalOrdinal> nvals = non_overlap_mv->get1dViewNonConst();
574  for (int j = 0; j < nvals.size(); ++j)
575  nvals[j] += offset;
576  }
577  #endif
578 
579  // build owned vector
580  {
581  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns::build_owned_vector",build_owned_vector);
582 
583  typedef std::unordered_set<panzer::GlobalOrdinal> HashTable;
584  HashTable isOwned, remainingOwned;
585 
586  // owned_ is made up of owned_ids.: This doesn't work for high order
587  auto nvals = non_overlap_mv->getLocalViewHost(Tpetra::Access::ReadOnly);
588  auto tagged_vals = tagged_non_overlap_mv->getLocalViewHost(Tpetra::Access::ReadOnly);
589  TEUCHOS_ASSERT(nvals.size()==tagged_vals.size());
590  for (size_t i = 0; i < nvals.extent(1); ++i) {
591  for (size_t j = 0; j < nvals.extent(0); ++j) {
592  if (nvals(j,i) != -1) {
593  for(panzer::GlobalOrdinal offset=0;offset<tagged_vals(j,i);++offset)
594  isOwned.insert(nvals(j,i)+offset);
595  }
596  else {
597  // sanity check
598  TEUCHOS_ASSERT(tagged_vals(j,i)==0);
599  }
600  }
601  }
602  remainingOwned = isOwned;
603 
604  HashTable hashTable; // use to detect if global ID has been added to owned_
605  for (size_t b = 0; b < blockOrder_.size(); ++b) {
606 
607  if(fa_fps_[b]==Teuchos::null)
608  continue;
609 
610  const std::vector<panzer::LocalOrdinal> & myElements = connMngr_->getElementBlock(blockOrder_[b]);
611 
612  for (size_t l = 0; l < myElements.size(); ++l) {
613  const std::vector<panzer::GlobalOrdinal> & localOrdering = elementGIDs_[myElements[l]];
614 
615  // add "novel" global ids that are also owned to owned array
616  for(std::size_t i=0;i<localOrdering.size();i++) {
617  // don't try to add if ID is not owned
618  if(isOwned.find(localOrdering[i])==isOwned.end())
619  continue;
620 
621  // only add a global ID if it has not been added
622  std::pair<typename HashTable::iterator,bool> insertResult = hashTable.insert(localOrdering[i]);
623  if(insertResult.second) {
624  owned_.push_back(localOrdering[i]);
625  remainingOwned.erase(localOrdering[i]);
626  }
627  }
628  }
629  }
630 
631  // add any other owned GIDs that were not already included.
632  // these are ones that are owned locally but not required by any
633  // element owned by this processor (uggh!)
634  for(typename HashTable::const_iterator itr=remainingOwned.begin();itr!=remainingOwned.end();itr++)
635  owned_.push_back(*itr);
636 
637  if(owned_.size()!=isOwned.size()) {
638  out << "I'm about to hang because of unknown numbering failure ... sorry! (line = " << __LINE__ << ")" << std::endl;
639  TEUCHOS_TEST_FOR_EXCEPTION(owned_.size()!=isOwned.size(),std::logic_error,
640  "DOFManager::buildGlobalUnkonwns: Failure because not all owned unknowns have been accounted for.");
641  }
642 
643  }
644 
645  // Build the ghosted_ array. The old simple way led to slow Jacobian
646  // assembly; the new way speeds up Jacobian assembly.
647  {
648  // Loop over all the elements and do a greedy ordering of local values over
649  // the elements for building ghosted_. Hopefully this gives a better
650  // layout for an element-ordered assembly.
651  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns::build_ghosted_array",BGA);
652 
653  // Use a hash table to detect if global IDs have been added to owned_.
654  typedef std::unordered_set<panzer::GlobalOrdinal> HashTable;
655  HashTable hashTable;
656  for (std::size_t i = 0; i < owned_.size(); i++)
657  hashTable.insert(owned_[i]);
658 
659  // Here we construct an accessor vector, such that we first process
660  // everything in the current element block, optionally followed by
661  // everything in the neighbor element block.
662  std::vector<ElementBlockAccess> blockAccessVec;
663  blockAccessVec.push_back(ElementBlockAccess(true,connMngr_));
664  if(useNeighbors_)
665  blockAccessVec.push_back(ElementBlockAccess(false,connMngr_));
666  for (std::size_t a = 0; a < blockAccessVec.size(); ++a)
667  {
668  // Get the access type (owned or neighbor).
669  const ElementBlockAccess& access = blockAccessVec[a];
670  for (size_t b = 0; b < blockOrder_.size(); ++b)
671  {
672  if (fa_fps_[b] == Teuchos::null)
673  continue;
674  const std::vector<panzer::LocalOrdinal>& myElements =
675  access.getElementBlock(blockOrder_[b]);
676  for (size_t l = 0; l < myElements.size(); ++l)
677  {
678  const std::vector<panzer::GlobalOrdinal>& localOrdering = elementGIDs_[myElements[l]];
679 
680  // Add "novel" global IDs into the ghosted_ vector.
681  for (std::size_t i = 0; i < localOrdering.size(); ++i)
682  {
683  std::pair<typename HashTable::iterator, bool> insertResult =
684  hashTable.insert(localOrdering[i]);
685 
686  // If the insertion succeeds, then this is "novel" to the owned_
687  // and ghosted_ vectors, so include it in ghosted_.
688  if(insertResult.second)
689  ghosted_.push_back(localOrdering[i]);
690  }
691  }
692  }
693  }
694  }
695 
696  buildConnectivityRun_ = true;
697 
698  // build orientations if required
700  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns::build_orientation",BO);
702  }
703 
704  // allocate the local IDs
705  if (useNeighbors_) {
706  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns::build_local_ids_from_owned_and_ghosted",BLOFOG);
708  }
709  else {
710  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns::build_local_ids",BLI);
711  this->buildLocalIds();
712  }
713 }
714 
716 std::pair<Teuchos::RCP<Tpetra::MultiVector<panzer::GlobalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> >,
718 DOFManager::buildGlobalUnknowns_GUN(const Tpetra::MultiVector<panzer::GlobalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> & tagged_overlap_mv,
719  Tpetra::MultiVector<panzer::GlobalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> & overlap_mv) const
720 {
721  // some typedefs
722  typedef panzer::TpetraNodeType Node;
723  typedef Tpetra::Map<panzer::LocalOrdinal, panzer::GlobalOrdinal, Node> Map;
724 
725  typedef Tpetra::Export<panzer::LocalOrdinal,panzer::GlobalOrdinal,Node> Export;
726  typedef Tpetra::Import<panzer::LocalOrdinal,panzer::GlobalOrdinal,Node> Import;
727 
728  //the GIDs are of type panzer::GlobalOrdinal.
729  typedef Tpetra::MultiVector<panzer::GlobalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,Node> MultiVector;
730 
731  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns_GUN",BGU_GUN);
732 
733  // LINE 2: In the GUN paper
734  RCP<const Map> overlap_map = tagged_overlap_mv.getMap();
735 
736  /* 6. Create a OneToOne map from the overlap map.
737  */
738 
739  // LINE 4: In the GUN paper
740 
741  RCP<const Map> non_overlap_map;
742  if(!useTieBreak_) {
743  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns_GUN::line_04 createOneToOne",GUN04);
744 
745  GreedyTieBreak<panzer::LocalOrdinal,panzer::GlobalOrdinal> greedy_tie_break;
746  non_overlap_map = Tpetra::createOneToOne<panzer::LocalOrdinal,panzer::GlobalOrdinal,Node>(overlap_map, greedy_tie_break);
747  }
748  else {
749  // use a hash tie break to get better load balancing from create one to one
750  // Aug. 4, 2016...this is a bad idea and doesn't work
751  HashTieBreak<panzer::LocalOrdinal,panzer::GlobalOrdinal> tie_break;
752  non_overlap_map = Tpetra::createOneToOne<panzer::LocalOrdinal,panzer::GlobalOrdinal,Node>(overlap_map,tie_break);
753  }
754 
755  /* 7. Create a non-overlapped multivector from OneToOne map.
756  */
757 
758  // LINE 5: In the GUN paper
759 
760  Teuchos::RCP<MultiVector> tagged_non_overlap_mv;
761  {
762  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns_GUN::line_05 alloc_unique_mv",GUN05);
763 
764  tagged_non_overlap_mv = Tpetra::createMultiVector<panzer::GlobalOrdinal>(non_overlap_map,(size_t)numFields_);
765  }
766 
767  /* 8. Create an export between the two maps.
768  */
769 
770  // LINE 6: In the GUN paper
771  RCP<Export> exp;
772  RCP<Import> imp;
773  RCP<MultiVector> non_overlap_mv;
774  {
775  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns_GUN::line_06 export",GUN06);
776 
777  exp = rcp(new Export(overlap_map,non_overlap_map));
778 
779  /* 9. Export data using ABSMAX.
780  */
781  tagged_non_overlap_mv->doExport(tagged_overlap_mv,*exp,Tpetra::ABSMAX);
782 
783  // copy the tagged one, so as to preserve the tagged MV so we can overwrite
784  // the non_overlap_mv
785  non_overlap_mv = rcp(new MultiVector(*tagged_non_overlap_mv,Teuchos::Copy));
786  }
787 
788  /* 10. Compute the local sum using Kokkos.
789  */
790 
791  // LINES 7-9: In the GUN paper
792 
793  panzer::GlobalOrdinal localsum=0;
794  {
795  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns_GUN::line_07-09 local_count",GUN07_09);
796  auto values = non_overlap_mv->getLocalViewDevice(Tpetra::Access::ReadOnly);
798  }
799 
800  /* 11. Create a map using local sums to generate final GIDs.
801  */
802 
803  // LINE 10: In the GUN paper
804 
805  panzer::GlobalOrdinal myOffset = -1;
806  {
807  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns_GUN::line_10 prefix_sum",GUN_10);
808 
809  // do a prefix sum
810  panzer::GlobalOrdinal scanResult = 0;
811  Teuchos::scan<int, panzer::GlobalOrdinal> (*getComm(), Teuchos::REDUCE_SUM, static_cast<panzer::GlobalOrdinal> (localsum), Teuchos::outArg (scanResult));
812  myOffset = scanResult - localsum;
813  }
814 
815  // LINE 11 and 12: In the GUN paper, these steps are eliminated because
816  // the non_overlap_mv is reused
817 
818  /* 12. Iterate through the non-overlapping MV and assign GIDs to
819  * the necessary points. (Assign a -1 elsewhere.)
820  */
821 
822  // LINES 13-21: In the GUN paper
823 
824  {
825  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns_GUN::line_13-21 gid_assignment",GUN13_21);
826  int which_id=0;
827  auto editnonoverlap = non_overlap_mv->getLocalViewHost(Tpetra::Access::ReadWrite);
828  for(size_t i=0; i<non_overlap_mv->getLocalLength(); ++i){
829  for(int j=0; j<numFields_; ++j){
830  if(editnonoverlap(i,j)!=0){
831  // editnonoverlap[j][i]=myOffset+which_id;
832  int ndof = Teuchos::as<int>(editnonoverlap(i,j));
833  editnonoverlap(i,j)=myOffset+which_id;
834  which_id+=ndof;
835  }
836  else{
837  editnonoverlap(i,j)=-1;
838  }
839 
840  }
841  }
842  }
843 
844  // LINE 22: In the GUN paper. Were performed above, and the overlaped_mv is
845  // abused to handle input tagging.
846 
847  /* 13. Import data back to the overlap MV using REPLACE.
848  */
849 
850  // LINE 23: In the GUN paper
851 
852  {
853  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildGlobalUnknowns_GUN::line_23 final_import",GUN23);
854 
855  // use exporter to save on communication setup costs
856  overlap_mv.doImport(*non_overlap_mv,*exp,Tpetra::REPLACE);
857  }
858 
859  //std::cout << Teuchos::describe(*non_overlap_mv,Teuchos::VERB_EXTREME) << std::endl;
860 
861  // return non_overlap_mv;
862  return std::make_pair(non_overlap_mv,tagged_non_overlap_mv);
863 }
864 
868 {
869  // some typedefs
870  typedef panzer::TpetraNodeType Node;
871  typedef Tpetra::Map<panzer::LocalOrdinal, panzer::GlobalOrdinal, Node> Map;
872  typedef Tpetra::MultiVector<panzer::GlobalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,Node> MultiVector;
873 
874  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildTaggedMultiVector",BTMV);
875 
876  //We will iterate through all of the blocks, building a FieldAggPattern for
877  //each of them.
878 
879  for (size_t b = 0; b < blockOrder_.size(); ++b) {
880  std::vector<std::tuple< int, panzer::FieldType, RCP<const panzer::FieldPattern> > > faConstruct;
881  //The ID is going to be the AID, and then everything will work.
882  //The ID should not be the AID, it should be the ID it has in the ordering.
883 
884  for (size_t i = 0; i < fieldAIDOrder_.size(); ++i) {
885  int looking = fieldAIDOrder_[i];
886 
887  //Check if in b's fp list
888  std::vector<int>::const_iterator reu = std::find(blockToAssociatedFP_[b].begin(), blockToAssociatedFP_[b].end(), looking);
889  if(!(reu==blockToAssociatedFP_[b].end())){
890  faConstruct.push_back(std::make_tuple(i, fieldTypes_[fieldAIDOrder_[i]], fieldPatterns_[fieldAIDOrder_[i]]));
891  }
892 
893  }
894 
895  if(faConstruct.size()>0) {
896  fa_fps_.push_back(rcp(new FieldAggPattern(faConstruct, ga_fp_)));
897 
898  // how many global IDs are in this element block?
899  int gidsInBlock = fa_fps_[fa_fps_.size()-1]->numberIds();
900  elementBlockGIDCount_.push_back(gidsInBlock);
901  }
902  else {
903  fa_fps_.push_back(Teuchos::null);
904  elementBlockGIDCount_.push_back(0);
905  }
906  }
907 
908  RCP<const Map> overlapmap = this->buildOverlapMapFromElements(ownedAccess);
909 
910  // LINE 22: In the GUN paper...the overlap_mv is reused for the tagged multivector.
911  // This is a bit of a practical abuse of the algorithm presented in the paper.
912 
913  Teuchos::RCP<MultiVector> overlap_mv;
914  {
915  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildTaggedMultiVector::allocate_tagged_multivector",ATMV);
916 
917  overlap_mv = Tpetra::createMultiVector<panzer::GlobalOrdinal>(overlapmap,(size_t)numFields_);
918  overlap_mv->putScalar(0); // if tpetra is not initialized with zeros
919  }
920 
921  /* 5. Iterate through all local elements again, checking with the FP
922  * information. Mark up the overlap map accordingly.
923  */
924 
925  {
926  PANZER_FUNC_TIME_MONITOR_DIFF("panzer::DOFManager::buildTaggedMultiVector::fill_tagged_multivector",FTMV);
927 
928  // temporary working vector to fill each row in tagged array
929  std::vector<int> working(overlap_mv->getNumVectors());
930  auto edittwoview_host = overlap_mv->getLocalViewHost(Tpetra::Access::ReadWrite);
931  for (size_t b = 0; b < blockOrder_.size(); ++b) {
932  // there has to be a field pattern associated with the block
933  if(fa_fps_[b]==Teuchos::null)
934  continue;
935 
936  const std::vector<panzer::LocalOrdinal> & numFields= fa_fps_[b]->numFieldsPerId();
937  const std::vector<panzer::LocalOrdinal> & fieldIds= fa_fps_[b]->fieldIds();
938  const std::vector<panzer::LocalOrdinal> & myElements = connMngr_->getElementBlock(blockOrder_[b]);
939  for (size_t l = 0; l < myElements.size(); ++l) {
940  auto connSize = connMngr_->getConnectivitySize(myElements[l]);
941  const auto * elmtConn = connMngr_->getConnectivity(myElements[l]);
942  int offset=0;
943  for (int c = 0; c < connSize; ++c) {
944  size_t lid = overlapmap->getLocalElement(elmtConn[c]);
945  for(std::size_t i=0;i<working.size();i++)
946  working[i] = 0;
947  for (int n = 0; n < numFields[c]; ++n) {
948  int whichField = fieldIds[offset];
949  //Row will be lid. column will be whichField.
950  //Shove onto local ordering
951  working[whichField]++;
952  offset++;
953  }
954  for(std::size_t i=0;i<working.size();i++) {
955  auto current = edittwoview_host(lid,i);
956  edittwoview_host(lid,i) = (current > working[i]) ? current : working[i];
957  }
958 
959  }
960  }
961  }
962  // // verbose output for inspecting overlap_mv
963  // for(int i=0;i<overlap_mv->getLocalLength(); i++) {
964  // for(int j=0;j<overlap_mv->getNumVectors() ; j++)
965  // std::cout << edittwoview[j][i] << " ";
966  // std::cout << std::endl;
967  // }
968  }
969 
970  return overlap_mv;
971 }
972 
974 int DOFManager::getFieldNum(const std::string & string) const
975 {
976  int ind=0;
977  bool found=false;
978  while(!found && (size_t)ind<fieldStringOrder_.size()){
979  if(fieldStringOrder_[ind]==string)
980  found=true;
981  else
982  ind++;
983  }
984 
985  if(found)
986  return ind;
987 
988  // didn't find anything...return -1
989  return -1;
990 }
991 
993 void DOFManager::getFieldOrder(std::vector<std::string> & fieldOrder) const
994 {
995  fieldOrder.resize(fieldStringOrder_.size());
996  for (size_t i = 0; i < fieldStringOrder_.size(); ++i)
997  fieldOrder[i]=fieldStringOrder_[i];
998 }
999 
1001 bool DOFManager::fieldInBlock(const std::string & field, const std::string & block) const
1002 {
1003  std::map<std::string,int>::const_iterator fitr = fieldNameToAID_.find(field);
1004  if(fitr==fieldNameToAID_.end()) {
1005  std::stringstream ss;
1007  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"DOFManager::fieldInBlock: invalid field name. DOF information is:\n"+ss.str());
1008  }
1009  std::map<std::string,int>::const_iterator bitr = blockNameToID_.find(block);
1010  if(bitr==blockNameToID_.end()) {
1011  std::stringstream ss;
1013  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"DOFManager::fieldInBlock: invalid block name. DOF information is:\n"+ss.str());
1014  }
1015  int fid=fitr->second;
1016  int bid=bitr->second;
1017 
1018  bool found=false;
1019  for (size_t i = 0; i < blockToAssociatedFP_[bid].size(); ++i) {
1020  if(blockToAssociatedFP_[bid][i]==fid){
1021  found=true;
1022  break;
1023  }
1024  }
1025 
1026  return found;
1027 }
1028 
1030 const std::vector<int> & DOFManager::getBlockFieldNumbers(const std::string & blockId) const
1031 {
1032  TEUCHOS_TEST_FOR_EXCEPTION(!buildConnectivityRun_,std::logic_error,"DOFManager::getBlockFieldNumbers: BuildConnectivity must be run first.");
1033 
1034  std::map<std::string,int>::const_iterator bitr = blockNameToID_.find(blockId);
1035  if(bitr==blockNameToID_.end())
1036  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"DOFManager::fieldInBlock: invalid block name");
1037  int bid=bitr->second;
1038 
1039  // there has to be a field pattern assocaited with the block
1040  if(fa_fps_[bid]!=Teuchos::null)
1041  return fa_fps_[bid]->fieldIds();
1042 
1043  // nothing to return
1044  static std::vector<int> empty;
1045  return empty;
1046 }
1047 
1049 const std::pair<std::vector<int>,std::vector<int> > &
1050 DOFManager::getGIDFieldOffsets_closure(const std::string & blockId, int fieldNum, int subcellDim,int subcellId) const
1051 {
1052  TEUCHOS_TEST_FOR_EXCEPTION(!buildConnectivityRun_,std::logic_error,"DOFManager::getGIDFieldOffsets_closure: BuildConnectivity must be run first.");
1053  std::map<std::string,int>::const_iterator bitr = blockNameToID_.find(blockId);
1054  if(bitr==blockNameToID_.end())
1055  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error, "DOFManager::getGIDFieldOffsets_closure: invalid block name.");
1056 
1057  // there has to be a field pattern assocaited with the block
1058  if(fa_fps_[bitr->second]!=Teuchos::null)
1059  return fa_fps_[bitr->second]->localOffsets_closure(fieldNum, subcellDim, subcellId);
1060 
1061  static std::pair<std::vector<int>,std::vector<int> > empty;
1062  return empty;
1063 }
1064 
1066 void DOFManager::ownedIndices(const std::vector<panzer::GlobalOrdinal> & indices,std::vector<bool> & isOwned) const
1067 {
1068  //Resizes the isOwned array.
1069  if(indices.size()!=isOwned.size())
1070  isOwned.resize(indices.size(),false);
1071  typename std::vector<panzer::GlobalOrdinal>::const_iterator endOf = owned_.end();
1072  for (std::size_t i = 0; i < indices.size(); ++i) {
1073  isOwned[i] = ( std::find(owned_.begin(), owned_.end(), indices[i])!=endOf );
1074  }
1075 }
1076 
1078 void DOFManager::setFieldOrder(const std::vector<std::string> & fieldOrder)
1079 {
1081  "DOFManager::setFieldOrder: setFieldOrder cannot be called after "
1082  "buildGlobalUnknowns has been called");
1083  if(validFieldOrder(fieldOrder)){
1084  fieldStringOrder_=fieldOrder;
1085  //We also need to reassign the fieldAIDOrder_.
1086  for (size_t i = 0; i < fieldStringOrder_.size(); ++i) {
1088  }
1089  }
1090  else {
1091  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"DOFManager::setFieldOrder: Invalid Field Ordering!");
1092  }
1093 }
1094 
1096 bool DOFManager::validFieldOrder(const std::vector<std::string> & proposed_fieldOrder)
1097 {
1098  if(fieldStringOrder_.size()!=proposed_fieldOrder.size())
1099  return false;
1100  //I'm using a not very efficient way of doing this, but there should never
1101  //be that many fields, so it isn't that big of a deal.
1102  for (size_t i = 0; i < fieldStringOrder_.size(); ++i) {
1103  bool found=false;
1104  for (size_t j = 0; j < proposed_fieldOrder.size(); ++j) {
1105  if(fieldStringOrder_[i]==proposed_fieldOrder[j])
1106  found=true;
1107  }
1108  if(!found)
1109  return false;
1110  }
1111  return true;
1112 }
1113 
1115 const std::string & DOFManager::getFieldString(int num) const
1116 {
1117  //A reverse lookup through fieldStringOrder_.
1118  if(num>=(int)fieldStringOrder_.size())
1119  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "DOFManager::getFieldString: invalid number");
1120  return fieldStringOrder_[num];
1121 }
1122 
1124 // Everything associated with orientation is not yet built, but this
1125 // is the method as found in Panzer_DOFManager_impl.hpp. There are
1126 // going to need to be some substantial changes to the code as it applies
1127 // to this DOFManager, but the basic ideas and format should be similar.
1128 //
1130 {
1131  orientation_.clear(); // clean up previous work
1132 
1133  std::vector<std::string> elementBlockIds;
1134  connMngr_->getElementBlockIds(elementBlockIds);
1135 
1136  // figure out how many total elements are owned by this processor (why is this so hard!)
1137  std::size_t myElementCount = 0;
1138  for(std::vector<std::string>::const_iterator blockItr=elementBlockIds.begin(); blockItr!=elementBlockIds.end();++blockItr)
1139  myElementCount += connMngr_->getElementBlock(*blockItr).size();
1140 
1141  // allocate for each block
1142  orientation_.resize(myElementCount);
1143 
1144  // loop over all element blocks
1145  for(std::vector<std::string>::const_iterator blockItr=elementBlockIds.begin();
1146  blockItr!=elementBlockIds.end();++blockItr) {
1147  const std::string & blockName = *blockItr;
1148 
1149  // this block has no unknowns (or elements)
1150  std::map<std::string,int>::const_iterator fap = blockNameToID_.find(blockName);
1151  if(fap==blockNameToID_.end()) {
1152  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"DOFManager::buildUnknownsOrientation: invalid block name");
1153  }
1154 
1155  int bid=fap->second;
1156 
1157  if(fa_fps_[bid]==Teuchos::null)
1158  continue;
1159 
1160  // grab field patterns, will be necessary to compute orientations
1161  const FieldPattern & fieldPattern = *fa_fps_[bid];
1162 
1163  //Should be ga_fp_ (geometric aggregate field pattern)
1164  std::vector<std::pair<int,int> > topEdgeIndices;
1166 
1167  // grab face orientations if 3D
1168  std::vector<std::vector<int> > topFaceIndices;
1169  if(ga_fp_->getDimension()==3)
1171 
1172  //How many GIDs are associated with a particular element bloc
1173  const std::vector<panzer::LocalOrdinal> & elmts = connMngr_->getElementBlock(blockName);
1174  for(std::size_t e=0;e<elmts.size();e++) {
1175  // this is the vector of orientations to fill: initialize it correctly
1176  std::vector<signed char> & eOrientation = orientation_[elmts[e]];
1177 
1178  // This resize seems to be the same as fieldPattern.numberIDs().
1179  // When computer edge orientations is called, that is the assert.
1180  // There should be no reason to make it anymore complicated.
1181  eOrientation.resize(fieldPattern.numberIds());
1182  for(std::size_t s=0;s<eOrientation.size();s++)
1183  eOrientation[s] = 1; // put in 1 by default
1184 
1185  // get geometry ids
1186  auto connSz = connMngr_->getConnectivitySize(elmts[e]);
1187  const panzer::GlobalOrdinal * connPtr = connMngr_->getConnectivity(elmts[e]);
1188  const std::vector<panzer::GlobalOrdinal> connectivity(connPtr,connPtr+connSz);
1189 
1190  orientation_helpers::computeCellEdgeOrientations(topEdgeIndices, connectivity, fieldPattern, eOrientation);
1191 
1192  // compute face orientations in 3D
1193  if(ga_fp_->getDimension()==3)
1194  orientation_helpers::computeCellFaceOrientations(topFaceIndices, connectivity, fieldPattern, eOrientation);
1195  }
1196  }
1197 }
1198 
1200 void DOFManager::getElementOrientation(panzer::LocalOrdinal localElmtId,std::vector<double> & gidsOrientation) const
1201 {
1202  TEUCHOS_TEST_FOR_EXCEPTION(orientation_.size()==0,std::logic_error,
1203  "DOFManager::getElementOrientations: Orientations were not constructed!");
1204 
1205  const std::vector<signed char> & local_o = orientation_[localElmtId];
1206  gidsOrientation.resize(local_o.size());
1207  for(std::size_t i=0;i<local_o.size();i++) {
1208  gidsOrientation[i] = double(local_o[i]);
1209  }
1210 }
1211 
1213 {
1215 
1216  connMngr_ = Teuchos::null;
1217 
1218  // wipe out FEI objects
1219  orientation_.clear(); // clean up previous work
1220  fa_fps_.clear();
1221  elementGIDs_.clear();
1222  owned_.clear();
1223  ghosted_.clear();
1224  elementBlockGIDCount_.clear();
1225 
1226  return connMngr;
1227 }
1228 
1230 std::size_t DOFManager::blockIdToIndex(const std::string & blockId) const
1231 {
1232  std::map<std::string,int>::const_iterator bitr = blockNameToID_.find(blockId);
1233  if(bitr==blockNameToID_.end())
1234  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"DOFManager::fieldInBlock: invalid block name");
1235  return bitr->second;
1236 }
1237 
1239 void DOFManager::printFieldInformation(std::ostream & os) const
1240 {
1241  os << "DOFManager Field Information: " << std::endl;
1242 
1243  // sanity check
1245 
1246  for(std::size_t i=0;i<blockOrder_.size();i++) {
1247  os << " Element Block = " << blockOrder_[i] << std::endl;
1248 
1249  // output field information
1250  const std::vector<int> & fieldIds = blockToAssociatedFP_[i];
1251  for(std::size_t f=0;f<fieldIds.size();f++)
1252  os << " \"" << getFieldString(fieldIds[f]) << "\" is field ID " << fieldIds[f] << std::endl;
1253  }
1254 }
1255 
1259 {
1260  PANZER_FUNC_TIME_MONITOR("panzer::DOFManager::builderOverlapMapFromElements");
1261 
1262  /*
1263  * 2. Iterate through all local elements and create the overlapVector
1264  * of concerned elements.
1265  */
1266 
1267  std::set<panzer::GlobalOrdinal> overlapset;
1268  for (size_t i = 0; i < blockOrder_.size(); ++i) {
1269  const std::vector<panzer::LocalOrdinal> & myElements = access.getElementBlock(blockOrder_[i]);
1270  for (size_t e = 0; e < myElements.size(); ++e) {
1271  auto connSize = connMngr_->getConnectivitySize(myElements[e]);
1272  const panzer::GlobalOrdinal * elmtConn = connMngr_->getConnectivity(myElements[e]);
1273  for (int k = 0; k < connSize; ++k) {
1274  overlapset.insert(elmtConn[k]);
1275  }
1276  }
1277  }
1278 
1279  Array<panzer::GlobalOrdinal> overlapVector;
1280  for (typename std::set<panzer::GlobalOrdinal>::const_iterator itr = overlapset.begin(); itr!=overlapset.end(); ++itr) {
1281  overlapVector.push_back(*itr);
1282  }
1283 
1284  /* 3. Construct an overlap map from this structure.
1285  */
1286  return Tpetra::createNonContigMapWithNode<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>(overlapVector,getComm());
1287 }
1288 
1290 void DOFManager::
1292  std::vector<std::vector< panzer::GlobalOrdinal > > & elementGIDs,
1293  const Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> & overlapmap,
1294  const Tpetra::MultiVector<panzer::GlobalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> & const_overlap_mv) const
1295 {
1296  using Teuchos::ArrayRCP;
1297 
1298  //To generate elementGIDs we need to go through all of the local elements.
1299  auto overlap_mv = const_cast<Tpetra::MultiVector<panzer::GlobalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType>&>(const_overlap_mv);
1300  const auto twoview_host = overlap_mv.getLocalViewHost(Tpetra::Access::ReadOnly);
1301 
1302  //And for each of the things in fa_fp.fieldIds we go to that column. To the the row,
1303  //we move from globalID to localID in the map and use our local value for something.
1304  for (size_t b = 0; b < blockOrder_.size(); ++b) {
1305  const std::vector<panzer::LocalOrdinal> & myElements = access.getElementBlock(blockOrder_[b]);
1306 
1307  if(fa_fps_[b]==Teuchos::null) {
1308  // fill elements that are not used with empty vectors
1309  for (size_t l = 0; l < myElements.size(); ++l) {
1310  panzer::LocalOrdinal thisID=myElements[l];
1311  if(elementGIDs.size()<=(size_t)thisID)
1312  elementGIDs.resize(thisID+1);
1313  }
1314  continue;
1315  }
1316 
1317  const std::vector<int> & numFields= fa_fps_[b]->numFieldsPerId();
1318  const std::vector<int> & fieldIds= fa_fps_[b]->fieldIds();
1319  //
1320  //
1321  for (size_t l = 0; l < myElements.size(); ++l) {
1322  auto connSize = connMngr_->getConnectivitySize(myElements[l]);
1323  const panzer::GlobalOrdinal * elmtConn = connMngr_->getConnectivity(myElements[l]);
1324  std::vector<panzer::GlobalOrdinal> localOrdering;
1325  int offset=0;
1326  for (int c = 0; c < connSize; ++c) {
1327  size_t lid = overlapmap.getLocalElement(elmtConn[c]);
1328  std::vector<int> dofsPerField(numFields_,0);
1329  for (int n = 0; n < numFields[c]; ++n) {
1330  int whichField = fieldIds[offset];
1331  offset++;
1332  //Row will be lid. column will be whichField.
1333  //Shove onto local ordering
1334  localOrdering.push_back(twoview_host(lid,whichField)+dofsPerField[whichField]);
1335 
1336  dofsPerField[whichField]++;
1337  }
1338  }
1339  panzer::LocalOrdinal thisID=myElements[l];
1340  if(elementGIDs.size()<=(size_t)thisID){
1341  elementGIDs.resize(thisID+1);
1342  }
1343  elementGIDs[thisID]=localOrdering;
1344  }
1345  }
1346 }
1347 
1349 {
1350  std::vector<std::vector<panzer::LocalOrdinal> > elementLIDs(elementGIDs_.size());
1351 
1352  std::vector<panzer::GlobalOrdinal> ownedAndGhosted;
1353  this->getOwnedAndGhostedIndices(ownedAndGhosted);
1354 
1355  // build global to local hash map (temporary and used only once)
1356  std::unordered_map<panzer::GlobalOrdinal,panzer::LocalOrdinal> hashMap;
1357  for(std::size_t i = 0; i < ownedAndGhosted.size(); ++i)
1358  hashMap[ownedAndGhosted[i]] = i;
1359 
1360  for (std::size_t i = 0; i < elementGIDs_.size(); ++i) {
1361  const std::vector<panzer::GlobalOrdinal>& gids = elementGIDs_[i];
1362  std::vector<panzer::LocalOrdinal>& lids = elementLIDs[i];
1363  lids.resize(gids.size());
1364  for (std::size_t g = 0; g < gids.size(); ++g)
1365  lids[g] = hashMap[gids[g]];
1366  }
1367 
1368  this->setLocalIds(elementLIDs);
1369 }
1370 
1371 /*
1372 template <typename panzer::LocalOrdinal,typename panzer::GlobalOrdinal>
1373 Teuchos::RCP<const Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> >
1374 DOFManager<panzer::LocalOrdinal,panzer::GlobalOrdinal>::runLocalRCMReordering(const Teuchos::RCP<const Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> > & map)
1375 {
1376  typedef panzer::TpetraNodeType Node;
1377  typedef Tpetra::Map<panzer::LocalOrdinal, panzer::GlobalOrdinal, Node> Map;
1378  typedef Tpetra::CrsGraph<panzer::LocalOrdinal, panzer::GlobalOrdinal, Node> Graph;
1379 
1380  Teuchos::RCP<Graph> graph = Teuchos::rcp(new Graph(map,0));
1381 
1382  // build Crs Graph from the mesh
1383  for (size_t b = 0; b < blockOrder_.size(); ++b) {
1384  if(fa_fps_[b]==Teuchos::null)
1385  continue;
1386 
1387  const std::vector<panzer::LocalOrdinal> & myElements = connMngr_->getElementBlock(blockOrder_[b]);
1388  for (size_t l = 0; l < myElements.size(); ++l) {
1389  panzer::LocalOrdinal connSize = connMngr_->getConnectivitySize(myElements[l]);
1390  const panzer::GlobalOrdinal * elmtConn = connMngr_->getConnectivity(myElements[l]);
1391  for (int c = 0; c < connSize; ++c) {
1392  panzer::LocalOrdinal lid = map->getLocalElement(elmtConn[c]);
1393  if(Teuchos::OrdinalTraits<panzer::LocalOrdinal>::invalid()!=lid)
1394  continue;
1395 
1396  graph->insertGlobalIndices(elmtConn[c],Teuchos::arrayView(elmtConn,connSize));
1397  }
1398  }
1399  }
1400 
1401  graph->fillComplete();
1402 
1403  std::vector<panzer::GlobalOrdinal> newOrder(map->getLocalNumElements());
1404  {
1405  // graph is constructed, now run RCM using zoltan2
1406  typedef Zoltan2::XpetraCrsGraphInput<Graph> SparseGraphAdapter;
1407 
1408  Teuchos::ParameterList params;
1409  params.set("order_method", "rcm");
1410  SparseGraphAdapter adapter(graph);
1411 
1412  Zoltan2::OrderingProblem<SparseGraphAdapter> problem(&adapter, &params,MPI_COMM_SELF);
1413  problem.solve();
1414 
1415  // build a new global ording array using permutation
1416  Zoltan2::OrderingSolution<panzer::GlobalOrdinal,panzer::LocalOrdinal> * soln = problem.getSolution();
1417 
1418  size_t dummy;
1419  size_t checkLength = soln->getPermutationSize();
1420  panzer::LocalOrdinal * checkPerm = soln->getPermutation(&dummy);
1421 
1422  Teuchos::ArrayView<const panzer::GlobalOrdinal > oldOrder = map->getLocalElementList();
1423  TEUCHOS_ASSERT(checkLength==oldOrder.size());
1424  TEUCHOS_ASSERT(checkLength==newOrder.size());
1425 
1426  for(size_t i=0;i<checkLength;i++)
1427  newOrder[checkPerm[i]] = oldOrder[i];
1428  }
1429 
1430  return Tpetra::createNonContigMap<panzer::LocalOrdinal,panzer::GlobalOrdinal>(newOrder,communicator_);
1431 }
1432 */
1433 
1434 } /*panzer*/
1435 
1436 #endif
std::vector< std::vector< int > > blockToAssociatedFP_
bool fieldInBlock(const std::string &field, const std::string &block) const
int getNumFields() const
gets the number of fields
virtual int getDimension() const =0
bool getOrientationsRequired() const
int getNumOwnedAndGhosted() const
Get the number of owned and ghosted indices for this processor.
void disableSafetyCheck()
void setFieldOrder(const std::vector< std::string > &fieldOrder)
Sums all entries of a Rank 2 Kokkos View.
std::vector< Teuchos::RCP< panzer::FieldAggPattern > > fa_fps_
const std::vector< panzer::LocalOrdinal > & getElementBlock(const std::string &eBlock) const
virtual Teuchos::RCP< const Tpetra::Map< panzer::LocalOrdinal, panzer::GlobalOrdinal, panzer::TpetraNodeType > > buildOverlapMapFromElements(const ElementBlockAccess &access) const
const PHX::View< const int * > getGIDFieldOffsetsKokkos(const std::string &blockID, int fieldNum) const
basic_FancyOStream & setShowProcRank(const bool showProcRank)
std::vector< std::vector< panzer::GlobalOrdinal > > elementGIDs_
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void getOwnedIndices(std::vector< panzer::GlobalOrdinal > &indices) const
Get the set of indices owned by this processor.
virtual Teuchos::RCP< Tpetra::MultiVector< panzer::GlobalOrdinal, panzer::LocalOrdinal, panzer::GlobalOrdinal, panzer::TpetraNodeType > > buildTaggedMultiVector(const ElementBlockAccess &access)
size_type size() const
FieldType
The type of discretization to use for a field pattern.
Teuchos::RCP< ConnManager > resetIndices()
Reset the indices for this DOF manager.
int numFields
virtual void buildGlobalUnknowns()
builds the global unknowns array
Teuchos::RCP< const panzer::FieldPattern > ga_fp_
virtual int numberIds() const
void getFieldOrder(std::vector< std::string > &fieldOrder) const
void getGhostedIndicesAsInt(std::vector< int > &indices) const
Get the set of indices ghosted for this processor.
const std::vector< int > & getGIDFieldOffsets(const std::string &blockID, int fieldNum) const
std::vector< int > fieldAIDOrder_
void setConnManager(const Teuchos::RCP< ConnManager > &connMngr, MPI_Comm mpiComm)
Adds a Connection Manager that will be associated with this DOFManager.
std::map< std::string, int > fieldNameToAID_
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
std::vector< int > elementBlockGIDCount_
Teuchos::RCP< Teuchos::Comm< int > > communicator_
void printFieldInformation(std::ostream &os) const
void computeCellEdgeOrientations(const std::vector< std::pair< int, int > > &topEdgeIndices, const std::vector< panzer::GlobalOrdinal > &topology, const FieldPattern &fieldPattern, std::vector< signed char > &orientation)
std::vector< Teuchos::RCP< const FieldPattern > > fieldPatterns_
virtual std::pair< Teuchos::RCP< Tpetra::MultiVector< panzer::GlobalOrdinal, panzer::LocalOrdinal, panzer::GlobalOrdinal, panzer::TpetraNodeType > >, Teuchos::RCP< Tpetra::MultiVector< panzer::GlobalOrdinal, panzer::LocalOrdinal, panzer::GlobalOrdinal, panzer::TpetraNodeType > > > buildGlobalUnknowns_GUN(const Tpetra::MultiVector< panzer::GlobalOrdinal, panzer::LocalOrdinal, panzer::GlobalOrdinal, panzer::TpetraNodeType > &tagged_overlap_mv, Tpetra::MultiVector< panzer::GlobalOrdinal, panzer::LocalOrdinal, panzer::GlobalOrdinal, panzer::TpetraNodeType > &overlap_mv) const
void getOwnedIndicesAsInt(std::vector< int > &indices) const
Get the set of indices owned by this processor.
basic_FancyOStream & setOutputToRootOnly(const int rootRank)
virtual void fillGIDsFromOverlappedMV(const ElementBlockAccess &access, std::vector< std::vector< panzer::GlobalOrdinal > > &elementGIDs, const Tpetra::Map< panzer::LocalOrdinal, panzer::GlobalOrdinal, panzer::TpetraNodeType > &overlapmap, const Tpetra::MultiVector< panzer::GlobalOrdinal, panzer::LocalOrdinal, panzer::GlobalOrdinal, panzer::TpetraNodeType > &overlap_mv) const
void setLocalIds(const std::vector< std::vector< panzer::LocalOrdinal > > &localIDs)
void computePatternFaceIndices(const FieldPattern &pattern, std::vector< std::vector< int > > &faceIndices)
int getNumGhosted() const
Get the number of indices ghosted for this processor.
std::vector< panzer::GlobalOrdinal > owned_
const unsigned int seed_
void ownedIndices(const std::vector< panzer::GlobalOrdinal > &indices, std::vector< bool > &isOwned) const
std::vector< std::string > blockOrder_
std::vector< panzer::GlobalOrdinal > ghosted_
void push_back(const value_type &x)
void computeCellFaceOrientations(const std::vector< std::vector< int > > &topFaceIndices, const std::vector< panzer::GlobalOrdinal > &topology, const FieldPattern &fieldPattern, std::vector< signed char > &orientation)
Teuchos::RCP< Teuchos::Comm< int > > getComm() const
std::size_t blockIdToIndex(const std::string &blockId) const
Teuchos::RCP< ConnManager > connMngr_
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...
void buildLocalIdsFromOwnedAndGhostedElements()
void apply(ReductionDataType &sum) const
const std::pair< std::vector< int >, std::vector< int > > & getGIDFieldOffsets_closure(const std::string &blockId, int fieldNum, int subcellDim, int subcellId) const
Use the field pattern so that you can find a particular field in the GIDs array. This version lets yo...
int getFieldNum(const std::string &string) const
Get the number used for access to this field.
const std::string & getFieldString(int num) const
Reverse lookup of the field string from a field number.
void getGhostedIndices(std::vector< panzer::GlobalOrdinal > &indices) const
Get the set of indices ghosted for this processor.
std::vector< std::string > fieldStringOrder_
void getElementGIDsAsInt(panzer::LocalOrdinal localElementID, std::vector< int > &gids, const std::string &blockIdHint="") const
Get the global IDs for a particular element. This function overwrites the gids variable.
int getNumOwned() const
Get the number of indices owned by this processor.
void getOwnedAndGhostedIndicesAsInt(std::vector< int > &indices) const
Get the set of owned and ghosted indices for this processor.
void getElementOrientation(panzer::LocalOrdinal localElmtId, std::vector< double > &gidsOrientation) const
Get a vector containg the orientation of the GIDs relative to the neighbors.
const std::vector< int > & getBlockFieldNumbers(const std::string &blockId) const
void getOwnedAndGhostedIndices(std::vector< panzer::GlobalOrdinal > &indices) const
Get the set of owned and ghosted indices for this processor.
#define TEUCHOS_ASSERT(assertion_test)
bool validFieldOrder(const std::vector< std::string > &proposed_fieldOrder)
std::vector< std::vector< signed char > > orientation_
int addField(const std::string &str, const Teuchos::RCP< const FieldPattern > &pattern, const panzer::FieldType &type=panzer::FieldType::CG)
Add a field to the DOF manager.
TransListIter end
Tpetra::KokkosCompat::KokkosDeviceWrapperNode< PHX::Device > TpetraNodeType
Kokkos::View< const LO **, Kokkos::LayoutRight, PHX::Device > lids
Teuchos::RCP< const FieldPattern > getFieldPattern(const std::string &name) const
Find a field pattern stored for a particular block and field number. This will retrive the pattern ad...
void computePatternEdgeIndices(const FieldPattern &pattern, std::vector< std::pair< int, int > > &edgeIndices)
void getElementGIDs(panzer::LocalOrdinal localElementID, std::vector< panzer::GlobalOrdinal > &gids, const std::string &blockIdHint="") const
get associated GIDs for a given local element
std::vector< FieldType > fieldTypes_
std::map< std::string, int > blockNameToID_