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