42 #ifndef TPETRA_IMPORT_UTIL2_HPP
43 #define TPETRA_IMPORT_UTIL2_HPP
50 #include "Tpetra_ConfigDefs.hpp"
51 #include "Tpetra_Import.hpp"
52 #include "Tpetra_HashTable.hpp"
53 #include "Tpetra_Map.hpp"
55 #include "Tpetra_Distributor.hpp"
57 #include "Tpetra_Vector.hpp"
58 #include "Kokkos_DualView.hpp"
59 #include <Teuchos_Array.hpp>
63 namespace Import_Util {
67 template<
typename Scalar,
typename Ordinal>
70 const Teuchos::ArrayView<Ordinal>& CRS_colind,
71 const Teuchos::ArrayView<Scalar>&CRS_vals);
73 template<
typename Ordinal>
76 const Teuchos::ArrayView<Ordinal>& CRS_colind);
78 template<
typename rowptr_array_type,
typename colind_array_type,
typename vals_array_type>
81 const colind_array_type& CRS_colind,
82 const vals_array_type& CRS_vals);
84 template<
typename rowptr_array_type,
typename colind_array_type>
87 const colind_array_type& CRS_colind);
93 template<
typename Scalar,
typename Ordinal>
96 const Teuchos::ArrayView<Ordinal>& CRS_colind,
97 const Teuchos::ArrayView<Scalar>& CRS_vals);
99 template<
typename Ordinal>
102 const Teuchos::ArrayView<Ordinal>& CRS_colind);
119 template <
typename LocalOrdinal,
typename GlobalOrdinal,
typename Node>
122 const Teuchos::ArrayView<LocalOrdinal> &columnIndices_LID,
123 const Teuchos::ArrayView<GlobalOrdinal> &columnIndices_GID,
125 const Teuchos::ArrayView<const int> &owningPids,
126 Teuchos::Array<int> &remotePids,
145 template <
typename LocalOrdinal,
typename GlobalOrdinal,
typename Node>
147 bool useReverseModeForOwnership,
148 const ::Tpetra::Details::Transfer<LocalOrdinal, GlobalOrdinal, Node>& transferForMigratingData,
149 bool useReverseModeForMigration,
161 namespace Import_Util {
164 template<
typename Scalar,
typename Ordinal>
167 const Teuchos::ArrayView<Ordinal> & CRS_colind,
168 const Teuchos::ArrayView<Scalar> &CRS_vals)
173 size_t NumRows = CRS_rowptr.size()-1;
174 size_t nnz = CRS_colind.size();
176 const bool permute_values_array = CRS_vals.size() > 0;
178 for(
size_t i = 0; i < NumRows; i++){
179 size_t start=CRS_rowptr[i];
180 if(start >= nnz)
continue;
182 size_t NumEntries = CRS_rowptr[i+1] - start;
183 Teuchos::ArrayRCP<Scalar> locValues;
184 if (permute_values_array)
185 locValues = Teuchos::arcp<Scalar>(&CRS_vals[start], 0, NumEntries,
false);
186 Teuchos::ArrayRCP<Ordinal> locIndices(&CRS_colind[start], 0, NumEntries,
false);
188 Ordinal n = NumEntries;
190 while (m<n) m = m*3+1;
195 for(Ordinal j = 0; j < max; j++) {
196 for(Ordinal k = j; k >= 0; k-=m) {
197 if(locIndices[k+m] >= locIndices[k])
199 if (permute_values_array) {
200 Scalar dtemp = locValues[k+m];
201 locValues[k+m] = locValues[k];
202 locValues[k] = dtemp;
204 Ordinal itemp = locIndices[k+m];
205 locIndices[k+m] = locIndices[k];
206 locIndices[k] = itemp;
214 template<
typename Ordinal>
216 sortCrsEntries (
const Teuchos::ArrayView<size_t> &CRS_rowptr,
217 const Teuchos::ArrayView<Ordinal> & CRS_colind)
220 Teuchos::ArrayView<Tpetra::Details::DefaultTypes::scalar_type> CRS_vals;
221 sortCrsEntries (CRS_rowptr, CRS_colind, CRS_vals);
226 template<
class RowOffsetsType,
class ColumnIndicesType,
class ValuesType>
227 class SortCrsEntries {
229 typedef typename ColumnIndicesType::non_const_value_type ordinal_type;
230 typedef typename ValuesType::non_const_value_type scalar_type;
233 SortCrsEntries (
const RowOffsetsType& ptr,
234 const ColumnIndicesType& ind,
235 const ValuesType& val) :
240 static_assert (std::is_signed<ordinal_type>::value,
"The type of each "
241 "column index -- that is, the type of each entry of ind "
242 "-- must be signed in order for this functor to work.");
245 KOKKOS_FUNCTION
void operator() (
const size_t i)
const
247 const size_t nnz = ind_.extent (0);
248 const size_t start = ptr_(i);
249 const bool permute_values_array = val_.extent(0) > 0;
252 const size_t NumEntries = ptr_(i+1) - start;
254 const ordinal_type n = static_cast<ordinal_type> (NumEntries);
256 while (m<n) m = m*3+1;
260 ordinal_type max = n - m;
261 for (ordinal_type j = 0; j < max; j++) {
262 for (ordinal_type k = j; k >= 0; k -= m) {
263 const size_t sk = start+k;
264 if (ind_(sk+m) >= ind_(sk)) {
267 if (permute_values_array) {
268 const scalar_type dtemp = val_(sk+m);
269 val_(sk+m) = val_(sk);
272 const ordinal_type itemp = ind_(sk+m);
273 ind_(sk+m) = ind_(sk);
284 const ColumnIndicesType& ind,
285 const ValuesType& val)
292 if (ptr.extent (0) == 0) {
295 const size_t NumRows = ptr.extent (0) - 1;
297 typedef size_t index_type;
298 typedef typename ValuesType::execution_space execution_space;
301 typedef Kokkos::RangePolicy<execution_space, index_type> range_type;
302 Kokkos::parallel_for (
"sortCrsEntries", range_type (0, NumRows),
303 SortCrsEntries (ptr, ind, val));
308 ColumnIndicesType ind_;
314 template<
typename rowptr_array_type,
typename colind_array_type,
typename vals_array_type>
317 const colind_array_type& CRS_colind,
318 const vals_array_type& CRS_vals)
320 Impl::SortCrsEntries<rowptr_array_type, colind_array_type,
321 vals_array_type>::sortCrsEntries (CRS_rowptr, CRS_colind, CRS_vals);
324 template<
typename rowptr_array_type,
typename colind_array_type>
327 const colind_array_type& CRS_colind)
330 typedef typename colind_array_type::execution_space execution_space;
331 typedef Tpetra::Details::DefaultTypes::scalar_type scalar_type;
332 typedef typename Kokkos::View<scalar_type*, execution_space> scalar_view_type;
333 scalar_view_type CRS_vals;
335 scalar_view_type>(CRS_rowptr, CRS_colind, CRS_vals);
339 template<
typename Scalar,
typename Ordinal>
342 const Teuchos::ArrayView<Ordinal> & CRS_colind,
343 const Teuchos::ArrayView<Scalar> &CRS_vals)
350 if (CRS_rowptr.size () == 0) {
353 const size_t NumRows = CRS_rowptr.size () - 1;
354 const size_t nnz = CRS_colind.size ();
355 size_t new_curr = CRS_rowptr[0];
356 size_t old_curr = CRS_rowptr[0];
358 const bool permute_values_array = CRS_vals.size() > 0;
360 for(
size_t i = 0; i < NumRows; i++){
361 const size_t old_rowptr_i=CRS_rowptr[i];
362 CRS_rowptr[i] = old_curr;
363 if(old_rowptr_i >= nnz)
continue;
365 size_t NumEntries = CRS_rowptr[i+1] - old_rowptr_i;
366 Teuchos::ArrayRCP<Scalar> locValues;
367 if (permute_values_array)
368 locValues = Teuchos::arcp<Scalar>(&CRS_vals[old_rowptr_i], 0, NumEntries,
false);
369 Teuchos::ArrayRCP<Ordinal> locIndices(&CRS_colind[old_rowptr_i], 0, NumEntries,
false);
372 Ordinal n = NumEntries;
377 for(Ordinal j = 0; j < max; j++) {
378 for(Ordinal k = j; k >= 0; k-=m) {
379 if(locIndices[k+m] >= locIndices[k])
381 if (permute_values_array) {
382 Scalar dtemp = locValues[k+m];
383 locValues[k+m] = locValues[k];
384 locValues[k] = dtemp;
386 Ordinal itemp = locIndices[k+m];
387 locIndices[k+m] = locIndices[k];
388 locIndices[k] = itemp;
395 for(
size_t j=old_rowptr_i; j < CRS_rowptr[i+1]; j++) {
396 if(j > old_rowptr_i && CRS_colind[j]==CRS_colind[new_curr-1]) {
397 if (permute_values_array) CRS_vals[new_curr-1] += CRS_vals[j];
399 else if(new_curr==j) {
403 CRS_colind[new_curr] = CRS_colind[j];
404 if (permute_values_array) CRS_vals[new_curr] = CRS_vals[j];
411 CRS_rowptr[NumRows] = new_curr;
414 template<
typename Ordinal>
416 sortAndMergeCrsEntries (
const Teuchos::ArrayView<size_t> &CRS_rowptr,
417 const Teuchos::ArrayView<Ordinal> & CRS_colind)
419 Teuchos::ArrayView<Tpetra::Details::DefaultTypes::scalar_type> CRS_vals;
420 return sortAndMergeCrsEntries(CRS_rowptr, CRS_colind, CRS_vals);
424 template <
typename LocalOrdinal,
typename GlobalOrdinal,
typename Node>
427 const Teuchos::ArrayView<LocalOrdinal> &colind_LID,
428 const Teuchos::ArrayView<GlobalOrdinal> &colind_GID,
430 const Teuchos::ArrayView<const int> &owningPIDs,
431 Teuchos::Array<int> &remotePIDs,
435 typedef LocalOrdinal LO;
436 typedef GlobalOrdinal GO;
439 const char prefix[] =
"lowCommunicationMakeColMapAndReindex: ";
443 const map_type& domainMap = *domainMapRCP;
449 Teuchos::Array<bool> LocalGIDs;
450 if (numDomainElements > 0) {
451 LocalGIDs.resize (numDomainElements,
false);
462 const size_t numMyRows = rowptr.size () - 1;
463 const int hashsize = std::max (static_cast<int> (numMyRows), 100);
466 Teuchos::Array<GO> RemoteGIDList;
467 RemoteGIDList.reserve (hashsize);
468 Teuchos::Array<int> PIDList;
469 PIDList.reserve (hashsize);
480 size_t NumLocalColGIDs = 0;
481 LO NumRemoteColGIDs = 0;
482 for (
size_t i = 0; i < numMyRows; ++i) {
483 for(
size_t j = rowptr[i]; j < rowptr[i+1]; ++j) {
484 const GO GID = colind_GID[j];
486 const LO LID = domainMap.getLocalElement (GID);
488 const bool alreadyFound = LocalGIDs[LID];
489 if (! alreadyFound) {
490 LocalGIDs[LID] =
true;
496 const LO hash_value = RemoteGIDs.
get (GID);
497 if (hash_value == -1) {
498 const int PID = owningPIDs[j];
499 TEUCHOS_TEST_FOR_EXCEPTION(
500 PID == -1, std::invalid_argument, prefix <<
"Cannot figure out if "
502 colind_LID[j] = static_cast<LO> (numDomainElements + NumRemoteColGIDs);
503 RemoteGIDs.
add (GID, NumRemoteColGIDs);
504 RemoteGIDList.push_back (GID);
505 PIDList.push_back (PID);
509 colind_LID[j] = static_cast<LO> (numDomainElements + hash_value);
517 if (domainMap.getComm ()->getSize () == 1) {
520 TEUCHOS_TEST_FOR_EXCEPTION(
521 NumRemoteColGIDs != 0, std::runtime_error, prefix <<
"There is only one "
522 "process in the domain Map's communicator, which means that there are no "
523 "\"remote\" indices. Nevertheless, some column indices are not in the "
525 if (static_cast<size_t> (NumLocalColGIDs) == numDomainElements) {
529 colMap = domainMapRCP;
536 const LO numMyCols = NumLocalColGIDs + NumRemoteColGIDs;
537 Teuchos::Array<GO> ColIndices;
538 GO* RemoteColIndices = NULL;
540 ColIndices.resize (numMyCols);
541 if (NumLocalColGIDs != static_cast<size_t> (numMyCols)) {
542 RemoteColIndices = &ColIndices[NumLocalColGIDs];
546 for (LO i = 0; i < NumRemoteColGIDs; ++i) {
547 RemoteColIndices[i] = RemoteGIDList[i];
551 Teuchos::Array<LO> RemotePermuteIDs (NumRemoteColGIDs);
552 for (LO i = 0; i < NumRemoteColGIDs; ++i) {
553 RemotePermuteIDs[i]=i;
560 ColIndices.begin () + NumLocalColGIDs,
561 RemotePermuteIDs.begin ());
567 remotePIDs = PIDList;
576 LO StartCurrent = 0, StartNext = 1;
577 while (StartNext < NumRemoteColGIDs) {
578 if (PIDList[StartNext]==PIDList[StartNext-1]) {
582 Tpetra::sort2 (ColIndices.begin () + NumLocalColGIDs + StartCurrent,
583 ColIndices.begin () + NumLocalColGIDs + StartNext,
584 RemotePermuteIDs.begin () + StartCurrent);
585 StartCurrent = StartNext;
589 Tpetra::sort2 (ColIndices.begin () + NumLocalColGIDs + StartCurrent,
590 ColIndices.begin () + NumLocalColGIDs + StartNext,
591 RemotePermuteIDs.begin () + StartCurrent);
594 Teuchos::Array<LO> ReverseRemotePermuteIDs (NumRemoteColGIDs);
595 for (LO i = 0; i < NumRemoteColGIDs; ++i) {
596 ReverseRemotePermuteIDs[RemotePermuteIDs[i]] = i;
600 bool use_local_permute =
false;
601 Teuchos::Array<LO> LocalPermuteIDs (numDomainElements);
613 Teuchos::ArrayView<const GO> domainGlobalElements = domainMap.getNodeElementList();
614 if (static_cast<size_t> (NumLocalColGIDs) == numDomainElements) {
615 if (NumLocalColGIDs > 0) {
617 std::copy (domainGlobalElements.begin (), domainGlobalElements.end (),
618 ColIndices.begin ());
622 LO NumLocalAgain = 0;
623 use_local_permute =
true;
624 for (
size_t i = 0; i < numDomainElements; ++i) {
626 LocalPermuteIDs[i] = NumLocalAgain;
627 ColIndices[NumLocalAgain++] = domainGlobalElements[i];
630 TEUCHOS_TEST_FOR_EXCEPTION(
631 static_cast<size_t> (NumLocalAgain) != NumLocalColGIDs,
632 std::runtime_error, prefix <<
"Local ID count test failed.");
636 const GST minus_one = Teuchos::OrdinalTraits<GST>::invalid ();
637 colMap = rcp (
new map_type (minus_one, ColIndices, domainMap.getIndexBase (),
638 domainMap.getComm (), domainMap.getNode ()));
641 for (
size_t i = 0; i < numMyRows; ++i) {
642 for (
size_t j = rowptr[i]; j < rowptr[i+1]; ++j) {
643 const LO ID = colind_LID[j];
644 if (static_cast<size_t> (ID) < numDomainElements) {
645 if (use_local_permute) {
646 colind_LID[j] = LocalPermuteIDs[colind_LID[j]];
653 colind_LID[j] = NumLocalColGIDs + ReverseRemotePermuteIDs[colind_LID[j]-numDomainElements];
675 template <
typename LocalOrdinal,
typename GlobalOrdinal,
typename Node>
677 bool useReverseModeForOwnership,
678 const ::Tpetra::Details::Transfer<LocalOrdinal, GlobalOrdinal, Node>& transferThatDefinesMigration,
679 bool useReverseModeForMigration,
684 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > OwningMap = useReverseModeForOwnership ? transferThatDefinesOwnership.
getTargetMap() : transferThatDefinesOwnership.getSourceMap();
685 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > MapAo = useReverseModeForOwnership ? transferThatDefinesOwnership.getSourceMap() : transferThatDefinesOwnership.getTargetMap();
686 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > MapAm = useReverseModeForMigration ? transferThatDefinesMigration.getTargetMap() : transferThatDefinesMigration.getSourceMap();
687 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > VectorMap = useReverseModeForMigration ? transferThatDefinesMigration.getSourceMap() : transferThatDefinesMigration.getTargetMap();
689 TEUCHOS_TEST_FOR_EXCEPTION(!MapAo->isSameAs(*MapAm),std::runtime_error,
"Tpetra::Import_Util::getTwoTransferOwnershipVector map mismatch between transfers");
690 TEUCHOS_TEST_FOR_EXCEPTION(!VectorMap->isSameAs(*owningPIDs.
getMap()),std::runtime_error,
"Tpetra::Import_Util::getTwoTransferOwnershipVector map mismatch transfer and vector");
691 #ifdef HAVE_TPETRA_DEBUG
692 TEUCHOS_TEST_FOR_EXCEPTION(!OwningMap->isOneToOne(),std::runtime_error,
"Tpetra::Import_Util::getTwoTransferOwnershipVector owner must be 1-to-1");
695 int rank = OwningMap->getComm()->getRank();
699 const import_type* ownAsImport = dynamic_cast<const import_type*> (&transferThatDefinesOwnership);
700 const export_type* ownAsExport = dynamic_cast<const export_type*> (&transferThatDefinesOwnership);
703 Teuchos::ArrayView<int> v_pids = pids();
704 if(ownAsImport && useReverseModeForOwnership) {TEUCHOS_TEST_FOR_EXCEPTION(1,std::runtime_error,
"Tpetra::Import_Util::getTwoTransferOwnershipVector owner must be 1-to-1");}
705 else if(ownAsImport && !useReverseModeForOwnership)
getPids(*ownAsImport,v_pids,
false);
706 else if(ownAsExport && useReverseModeForMigration) {TEUCHOS_TEST_FOR_EXCEPTION(1,std::runtime_error,
"Tpetra::Import_Util::getTwoTransferOwnershipVector this option not yet implemented");}
707 else {TEUCHOS_TEST_FOR_EXCEPTION(1,std::runtime_error,
"Tpetra::Import_Util::getTwoTransferOwnershipVector owner must be 1-to-1");}
709 const import_type* xferAsImport = dynamic_cast<const import_type*> (&transferThatDefinesMigration);
710 const export_type* xferAsExport = dynamic_cast<const export_type*> (&transferThatDefinesMigration);
711 TEUCHOS_TEST_FOR_EXCEPTION(!xferAsImport && !xferAsExport,std::runtime_error,
"Tpetra::Import_Util::getTwoTransferOwnershipVector transfer undefined");
727 #endif // TPETRA_IMPORT_UTIL_HPP