Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Import_Util2.hpp
Go to the documentation of this file.
1// @HEADER
2// ***********************************************************************
3//
4// Tpetra: Templated Linear Algebra Services Package
5// Copyright (2008) Sandia Corporation
6//
7// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8// the U.S. Government retains certain rights in this software.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions are
12// met:
13//
14// 1. Redistributions of source code must retain the above copyright
15// notice, this list of conditions and the following disclaimer.
16//
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// 3. Neither the name of the Corporation nor the names of the
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36//
37// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38//
39// ************************************************************************
40// @HEADER
41
42#ifndef TPETRA_IMPORT_UTIL2_HPP
43#define TPETRA_IMPORT_UTIL2_HPP
44
49
50#include "Tpetra_ConfigDefs.hpp"
51#include "Tpetra_Import.hpp"
52#include "Tpetra_HashTable.hpp"
53#include "Tpetra_Map.hpp"
54#include "Tpetra_Util.hpp"
55#include "Tpetra_Distributor.hpp"
58#include "Tpetra_Vector.hpp"
59#include "Kokkos_DualView.hpp"
60#include <Teuchos_Array.hpp>
61#include <utility>
62#include <set>
63
65
66namespace Tpetra {
67namespace Import_Util {
68
71template<typename Scalar, typename Ordinal>
72void
73sortCrsEntries (const Teuchos::ArrayView<size_t>& CRS_rowptr,
74 const Teuchos::ArrayView<Ordinal>& CRS_colind,
75 const Teuchos::ArrayView<Scalar>&CRS_vals);
76
77template<typename Ordinal>
78void
79sortCrsEntries (const Teuchos::ArrayView<size_t>& CRS_rowptr,
80 const Teuchos::ArrayView<Ordinal>& CRS_colind);
81
82template<typename rowptr_array_type, typename colind_array_type, typename vals_array_type>
83void
84sortCrsEntries (const rowptr_array_type& CRS_rowptr,
85 const colind_array_type& CRS_colind,
86 const vals_array_type& CRS_vals);
87
88template<typename rowptr_array_type, typename colind_array_type>
89void
90sortCrsEntries (const rowptr_array_type& CRS_rowptr,
91 const colind_array_type& CRS_colind);
92
97template<typename Scalar, typename Ordinal>
98void
99sortAndMergeCrsEntries (const Teuchos::ArrayView<size_t>& CRS_rowptr,
100 const Teuchos::ArrayView<Ordinal>& CRS_colind,
101 const Teuchos::ArrayView<Scalar>& CRS_vals);
102
103template<typename Ordinal>
104void
105sortAndMergeCrsEntries (const Teuchos::ArrayView<size_t>& CRS_rowptr,
106 const Teuchos::ArrayView<Ordinal>& CRS_colind);
107
123template <typename LocalOrdinal, typename GlobalOrdinal, typename Node>
124void
125lowCommunicationMakeColMapAndReindex (const Teuchos::ArrayView<const size_t> &rowPointers,
126 const Teuchos::ArrayView<LocalOrdinal> &columnIndices_LID,
127 const Teuchos::ArrayView<GlobalOrdinal> &columnIndices_GID,
128 const Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > & domainMap,
129 const Teuchos::ArrayView<const int> &owningPids,
130 Teuchos::Array<int> &remotePids,
131 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > & colMap);
132
133
134
135
149 template <typename LocalOrdinal, typename GlobalOrdinal, typename Node>
150 void getTwoTransferOwnershipVector(const ::Tpetra::Details::Transfer<LocalOrdinal, GlobalOrdinal, Node>& transferThatDefinesOwnership,
151 bool useReverseModeForOwnership,
152 const ::Tpetra::Details::Transfer<LocalOrdinal, GlobalOrdinal, Node>& transferForMigratingData,
153 bool useReverseModeForMigration,
154 Tpetra::Vector<int,LocalOrdinal,GlobalOrdinal,Node> & owningPIDs);
155
156} // namespace Import_Util
157} // namespace Tpetra
158
159
160//
161// Implementations
162//
163
164namespace Tpetra {
165namespace Import_Util {
166
167
168template<typename PID, typename GlobalOrdinal>
169bool sort_PID_then_GID(const std::pair<PID,GlobalOrdinal> &a,
170 const std::pair<PID,GlobalOrdinal> &b)
171{
172 if(a.first!=b.first)
173 return (a.first < b.first);
174 return (a.second < b.second);
175}
176
177template<typename PID,
178 typename GlobalOrdinal,
179 typename LocalOrdinal>
180bool sort_PID_then_pair_GID_LID(const std::pair<PID, std::pair< GlobalOrdinal, LocalOrdinal > > &a,
181 const std::pair<PID, std::pair< GlobalOrdinal, LocalOrdinal > > &b)
182{
183 if(a.first!=b.first)
184 return a.first < b.first;
185 else
186 return (a.second.first < b.second.first);
187}
188
189template<typename Scalar,
190 typename LocalOrdinal,
191 typename GlobalOrdinal,
192 typename Node>
193void
194reverseNeighborDiscovery(const CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> & SourceMatrix,
195 const typename CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::row_ptrs_host_view_type & rowptr,
196 const typename CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::local_inds_host_view_type & colind,
197 const Tpetra::Details::Transfer<LocalOrdinal,GlobalOrdinal,Node>& RowTransfer,
198 Teuchos::RCP<const Tpetra::Import<LocalOrdinal,GlobalOrdinal,Node> > MyImporter,
199 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > MyDomainMap,
200 Teuchos::ArrayRCP<int>& type3PIDs,
201 Teuchos::ArrayRCP<LocalOrdinal>& type3LIDs,
202 Teuchos::RCP<const Teuchos::Comm<int> >& rcomm)
203{
204#ifdef HAVE_TPETRACORE_MPI
205 using Teuchos::TimeMonitor;
206 using ::Tpetra::Details::Behavior;
207 typedef LocalOrdinal LO;
208 typedef GlobalOrdinal GO;
209 typedef std::pair<GO,GO> pidgidpair_t;
210 using Teuchos::RCP;
211 const std::string prefix {" Import_Util2::ReverseND:: "};
212 const std::string label ("IU2::Neighbor");
213
214 // There can be no neighbor discovery if you don't have an importer
215 if(MyImporter.is_null()) return;
216
217 std::ostringstream errstr;
218 bool error = false;
219 auto const comm = MyDomainMap->getComm();
220
221 MPI_Comm rawComm = getRawMpiComm(*comm);
222 const int MyPID = rcomm->getRank ();
223
224 // Things related to messages I am sending in forward mode (RowTransfer)
225 // *** Note: this will be incorrect for transferAndFillComplete if it is in reverse mode. FIXME cbl.
226 auto ExportPIDs = RowTransfer.getExportPIDs();
227 auto ExportLIDs = RowTransfer.getExportLIDs();
228 auto NumExportLIDs = RowTransfer.getNumExportIDs();
229
230 Distributor & Distor = MyImporter->getDistributor();
231 const size_t NumRecvs = Distor.getNumReceives();
232 const size_t NumSends = Distor.getNumSends();
233 auto RemoteLIDs = MyImporter->getRemoteLIDs();
234 auto const ProcsFrom = Distor.getProcsFrom();
235 auto const ProcsTo = Distor.getProcsTo();
236
237 auto LengthsFrom = Distor.getLengthsFrom();
238 auto MyColMap = SourceMatrix.getColMap();
239 const size_t numCols = MyColMap->getLocalNumElements ();
240 RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > target = MyImporter->getTargetMap();
241
242 // Get the owning pids in a special way,
243 // s.t. ProcsFrom[RemotePIDs[i]] is the proc that owns RemoteLIDs[j]....
244 Teuchos::Array<int> RemotePIDOrder(numCols,-1);
245
246 // For each remote ID, record index into ProcsFrom, who owns it.
247 for (size_t i = 0, j = 0; i < NumRecvs; ++i) {
248 for (size_t k = 0; k < LengthsFrom[i]; ++k) {
249 const int pid = ProcsFrom[i];
250 if (pid != MyPID) {
251 RemotePIDOrder[RemoteLIDs[j]] = i;
252 }
253 j++;
254 }
255 }
256
257 // Step One: Start tacking the (GID,PID) pairs on the std sets
258 //
259 // For each index in ProcsFrom, we will insert into a set of (PID,
260 // GID) pairs, in order to build a list of such pairs for each of
261 // those processes. Since this is building a reverse, we will send
262 // to these processes.
263 Teuchos::Array<int> ReverseSendSizes(NumRecvs,0);
264 // do this as C array to avoid Teuchos::Array value initialization of all reserved memory
265 Teuchos::Array< Teuchos::ArrayRCP<pidgidpair_t > > RSB(NumRecvs);
266
267 {
268#ifdef HAVE_TPETRA_MMM_TIMINGS
269 TimeMonitor set_all(*TimeMonitor::getNewTimer(prefix + std::string("isMMallSetRSB")));
270#endif
271
272 // 25 Jul 2018: CBL
273 // todo:std::unordered_set (hash table),
274 // with an adequate prereservation ("bucket count").
275 // An onordered_set has to have a custom hasher for pid/gid pair
276 // However, when pidsets is copied to RSB, it will be in key
277 // order _not_ in pid,gid order. (unlike std::set).
278 // Impliment this with a reserve, and time BOTH building pidsets
279 // _and_ the sort after the receive. Even if unordered_set saves
280 // time, if it causes the sort to be longer, it's not a win.
281
282 Teuchos::Array<std::set<pidgidpair_t>> pidsets(NumRecvs);
283 {
284#ifdef HAVE_TPETRA_MMM_TIMINGS
285 TimeMonitor set_insert(*TimeMonitor::getNewTimer(prefix + std::string("isMMallSetRSBinsert")));
286#endif
287 for(size_t i=0; i < NumExportLIDs; i++) {
288 LO lid = ExportLIDs[i];
289 GO exp_pid = ExportPIDs[i];
290 for(auto j=rowptr[lid]; j<rowptr[lid+1]; j++){
291 int pid_order = RemotePIDOrder[colind[j]];
292 if(pid_order!=-1) {
293 GO gid = MyColMap->getGlobalElement(colind[j]); //Epetra SM.GCID46 =>sm->graph-> {colmap(colind)}
294 auto tpair = pidgidpair_t(exp_pid,gid);
295 pidsets[pid_order].insert(pidsets[pid_order].end(),tpair);
296 }
297 }
298 }
299 }
300
301 {
302#ifdef HAVE_TPETRA_MMM_TIMINGS
303 TimeMonitor set_cpy(*TimeMonitor::getNewTimer(prefix + std::string("isMMallSetRSBcpy")));
304#endif
305 int jj = 0;
306 for(auto &&ps : pidsets) {
307 auto s = ps.size();
308 RSB[jj] = Teuchos::arcp(new pidgidpair_t[ s ],0, s ,true);
309 std::copy(ps.begin(),ps.end(),RSB[jj]);
310 ReverseSendSizes[jj]=s;
311 ++jj;
312 }
313 }
314 } // end of set based packing.
315
316 Teuchos::Array<int> ReverseRecvSizes(NumSends,-1);
317 Teuchos::Array<MPI_Request> rawBreq(ProcsFrom.size()+ProcsTo.size(), MPI_REQUEST_NULL);
318 // 25 Jul 2018: MPI_TAG_UB is the largest tag value; could be < 32768.
319 const int mpi_tag_base_ = 3;
320
321 int mpireq_idx=0;
322 for(int i=0;i<ProcsTo.size();++i) {
323 int Rec_Tag = mpi_tag_base_ + ProcsTo[i];
324 int * thisrecv = (int *) (&ReverseRecvSizes[i]);
325 MPI_Request rawRequest = MPI_REQUEST_NULL;
326 MPI_Irecv(const_cast<int*>(thisrecv),
327 1,
328 MPI_INT,
329 ProcsTo[i],
330 Rec_Tag,
331 rawComm,
332 &rawRequest);
333 rawBreq[mpireq_idx++]=rawRequest;
334 }
335 for(int i=0;i<ProcsFrom.size();++i) {
336 int Send_Tag = mpi_tag_base_ + MyPID;
337 int * mysend = ( int *)(&ReverseSendSizes[i]);
338 MPI_Request rawRequest = MPI_REQUEST_NULL;
339 MPI_Isend(mysend,
340 1,
341 MPI_INT,
342 ProcsFrom[i],
343 Send_Tag,
344 rawComm,
345 &rawRequest);
346 rawBreq[mpireq_idx++]=rawRequest;
347 }
348 Teuchos::Array<MPI_Status> rawBstatus(rawBreq.size());
349#ifdef HAVE_TPETRA_DEBUG
350 const int err1 =
351#endif
352 MPI_Waitall (rawBreq.size(), rawBreq.getRawPtr(),
353 rawBstatus.getRawPtr());
354
355
356#ifdef HAVE_TPETRA_DEBUG
357 if(err1) {
358 errstr <<MyPID<< "sE1 reverseNeighborDiscovery Mpi_Waitall error on send ";
359 error=true;
360 std::cerr<<errstr.str()<<std::flush;
361 }
362#endif
363
364 int totalexportpairrecsize = 0;
365 for (size_t i = 0; i < NumSends; ++i) {
366 totalexportpairrecsize += ReverseRecvSizes[i];
367#ifdef HAVE_TPETRA_DEBUG
368 if(ReverseRecvSizes[i]<0) {
369 errstr << MyPID << "E4 reverseNeighborDiscovery: got < 0 for receive size "<<ReverseRecvSizes[i]<<std::endl;
370 error=true;
371 }
372#endif
373 }
374 Teuchos::ArrayRCP<pidgidpair_t >AllReverseRecv= Teuchos::arcp(new pidgidpair_t[totalexportpairrecsize],0,totalexportpairrecsize,true);
375 int offset = 0;
376 mpireq_idx=0;
377 for(int i=0;i<ProcsTo.size();++i) {
378 int recv_data_size = ReverseRecvSizes[i]*2;
379 int recvData_MPI_Tag = mpi_tag_base_*2 + ProcsTo[i];
380 MPI_Request rawRequest = MPI_REQUEST_NULL;
381 GO * rec_bptr = (GO*) (&AllReverseRecv[offset]);
382 offset+=ReverseRecvSizes[i];
383 MPI_Irecv(rec_bptr,
384 recv_data_size,
385 ::Tpetra::Details::MpiTypeTraits<GO>::getType(rec_bptr[0]),
386 ProcsTo[i],
387 recvData_MPI_Tag,
388 rawComm,
389 &rawRequest);
390 rawBreq[mpireq_idx++]=rawRequest;
391 }
392 for(int ii=0;ii<ProcsFrom.size();++ii) {
393 GO * send_bptr = (GO*) (RSB[ii].getRawPtr());
394 MPI_Request rawSequest = MPI_REQUEST_NULL;
395 int send_data_size = ReverseSendSizes[ii]*2; // 2 == count of pair
396 int sendData_MPI_Tag = mpi_tag_base_*2+MyPID;
397 MPI_Isend(send_bptr,
398 send_data_size,
399 ::Tpetra::Details::MpiTypeTraits<GO>::getType(send_bptr[0]),
400 ProcsFrom[ii],
401 sendData_MPI_Tag,
402 rawComm,
403 &rawSequest);
404
405 rawBreq[mpireq_idx++]=rawSequest;
406 }
407#ifdef HAVE_TPETRA_DEBUG
408 const int err =
409#endif
410 MPI_Waitall (rawBreq.size(),
411 rawBreq.getRawPtr(),
412 rawBstatus.getRawPtr());
413#ifdef HAVE_TPETRA_DEBUG
414 if(err) {
415 errstr <<MyPID<< "E3.r reverseNeighborDiscovery Mpi_Waitall error on receive ";
416 error=true;
417 std::cerr<<errstr.str()<<std::flush;
418 }
419#endif
420 std::sort(AllReverseRecv.begin(), AllReverseRecv.end(), Tpetra::Import_Util::sort_PID_then_GID<GlobalOrdinal, GlobalOrdinal>);
421
422 auto newEndOfPairs = std::unique(AllReverseRecv.begin(), AllReverseRecv.end());
423// don't resize to remove non-unique, just use the end-of-unique iterator
424 if(AllReverseRecv.begin() == newEndOfPairs) return;
425 int ARRsize = std::distance(AllReverseRecv.begin(),newEndOfPairs);
426 auto rPIDs = Teuchos::arcp(new int[ARRsize],0,ARRsize,true);
427 auto rLIDs = Teuchos::arcp(new LocalOrdinal[ARRsize],0,ARRsize,true);
428
429 int tsize=0;
430 for(auto itr = AllReverseRecv.begin(); itr!=newEndOfPairs; ++itr ) {
431 if((int)(itr->first) != MyPID) {
432 rPIDs[tsize]=(int)itr->first;
433 LocalOrdinal lid = MyDomainMap->getLocalElement(itr->second);
434 rLIDs[tsize]=lid;
435 tsize++;
436 }
437 }
438
439 type3PIDs=rPIDs.persistingView(0,tsize);
440 type3LIDs=rLIDs.persistingView(0,tsize);
441
442 if(error){
443 std::cerr<<errstr.str()<<std::flush;
444 comm->barrier();
445 comm->barrier();
446 comm->barrier();
447 MPI_Abort (MPI_COMM_WORLD, -1);
448 }
449#endif
450}
451
452// Note: This should get merged with the other Tpetra sort routines eventually.
453template<typename Scalar, typename Ordinal>
454void
455sortCrsEntries (const Teuchos::ArrayView<size_t> &CRS_rowptr,
456 const Teuchos::ArrayView<Ordinal> & CRS_colind,
457 const Teuchos::ArrayView<Scalar> &CRS_vals)
458{
459 // For each row, sort column entries from smallest to largest.
460 // Use shell sort. Stable sort so it is fast if indices are already sorted.
461 // Code copied from Epetra_CrsMatrix::SortEntries()
462 size_t NumRows = CRS_rowptr.size()-1;
463 size_t nnz = CRS_colind.size();
464
465 const bool permute_values_array = CRS_vals.size() > 0;
466
467 for(size_t i = 0; i < NumRows; i++){
468 size_t start=CRS_rowptr[i];
469 if(start >= nnz) continue;
470
471 size_t NumEntries = CRS_rowptr[i+1] - start;
472 Teuchos::ArrayRCP<Scalar> locValues;
473 if (permute_values_array)
474 locValues = Teuchos::arcp<Scalar>(&CRS_vals[start], 0, NumEntries, false);
475 Teuchos::ArrayRCP<Ordinal> locIndices(&CRS_colind[start], 0, NumEntries, false);
476
477 Ordinal n = NumEntries;
478 Ordinal m = 1;
479 while (m<n) m = m*3+1;
480 m /= 3;
481
482 while(m > 0) {
483 Ordinal max = n - m;
484 for(Ordinal j = 0; j < max; j++) {
485 for(Ordinal k = j; k >= 0; k-=m) {
486 if(locIndices[k+m] >= locIndices[k])
487 break;
488 if (permute_values_array) {
489 Scalar dtemp = locValues[k+m];
490 locValues[k+m] = locValues[k];
491 locValues[k] = dtemp;
492 }
493 Ordinal itemp = locIndices[k+m];
494 locIndices[k+m] = locIndices[k];
495 locIndices[k] = itemp;
496 }
497 }
498 m = m/3;
499 }
500 }
501}
502
503template<typename Ordinal>
504void
505sortCrsEntries (const Teuchos::ArrayView<size_t> &CRS_rowptr,
506 const Teuchos::ArrayView<Ordinal> & CRS_colind)
507{
508 // Generate dummy values array
509 Teuchos::ArrayView<Tpetra::Details::DefaultTypes::scalar_type> CRS_vals;
510 sortCrsEntries (CRS_rowptr, CRS_colind, CRS_vals);
511}
512
513namespace Impl {
514
515template<class RowOffsetsType, class ColumnIndicesType, class ValuesType>
516class SortCrsEntries {
517private:
518 typedef typename ColumnIndicesType::non_const_value_type ordinal_type;
519 typedef typename ValuesType::non_const_value_type scalar_type;
520
521public:
522 SortCrsEntries (const RowOffsetsType& ptr,
523 const ColumnIndicesType& ind,
524 const ValuesType& val) :
525 ptr_ (ptr),
526 ind_ (ind),
527 val_ (val)
528 {
529 static_assert (std::is_signed<ordinal_type>::value, "The type of each "
530 "column index -- that is, the type of each entry of ind "
531 "-- must be signed in order for this functor to work.");
532 }
533
534 KOKKOS_FUNCTION void operator() (const size_t i) const
535 {
536 const size_t nnz = ind_.extent (0);
537 const size_t start = ptr_(i);
538 const bool permute_values_array = val_.extent(0) > 0;
539
540 if (start < nnz) {
541 const size_t NumEntries = ptr_(i+1) - start;
542
543 const ordinal_type n = static_cast<ordinal_type> (NumEntries);
544 ordinal_type m = 1;
545 while (m<n) m = m*3+1;
546 m /= 3;
547
548 while (m > 0) {
549 ordinal_type max = n - m;
550 for (ordinal_type j = 0; j < max; j++) {
551 for (ordinal_type k = j; k >= 0; k -= m) {
552 const size_t sk = start+k;
553 if (ind_(sk+m) >= ind_(sk)) {
554 break;
555 }
556 if (permute_values_array) {
557 const scalar_type dtemp = val_(sk+m);
558 val_(sk+m) = val_(sk);
559 val_(sk) = dtemp;
560 }
561 const ordinal_type itemp = ind_(sk+m);
562 ind_(sk+m) = ind_(sk);
563 ind_(sk) = itemp;
564 }
565 }
566 m = m/3;
567 }
568 }
569 }
570
571 static void
572 sortCrsEntries (const RowOffsetsType& ptr,
573 const ColumnIndicesType& ind,
574 const ValuesType& val)
575 {
576 // For each row, sort column entries from smallest to largest.
577 // Use shell sort. Stable sort so it is fast if indices are already sorted.
578 // Code copied from Epetra_CrsMatrix::SortEntries()
579 // NOTE: This should not be taken as a particularly efficient way to sort
580 // rows of matrices in parallel. But it is correct, so that's something.
581 if (ptr.extent (0) == 0) {
582 return; // no rows, so nothing to sort
583 }
584 const size_t NumRows = ptr.extent (0) - 1;
585
586 typedef size_t index_type; // what this function was using; not my choice
587 typedef typename ValuesType::execution_space execution_space;
588 // Specify RangePolicy explicitly, in order to use correct execution
589 // space. See #1345.
590 typedef Kokkos::RangePolicy<execution_space, index_type> range_type;
591 Kokkos::parallel_for ("sortCrsEntries", range_type (0, NumRows),
592 SortCrsEntries (ptr, ind, val));
593 }
594
595private:
596 RowOffsetsType ptr_;
597 ColumnIndicesType ind_;
598 ValuesType val_;
599};
600
601} // namespace Impl
602
603template<typename rowptr_array_type, typename colind_array_type, typename vals_array_type>
604void
605sortCrsEntries (const rowptr_array_type& CRS_rowptr,
606 const colind_array_type& CRS_colind,
607 const vals_array_type& CRS_vals)
608{
609 Impl::SortCrsEntries<rowptr_array_type, colind_array_type,
610 vals_array_type>::sortCrsEntries (CRS_rowptr, CRS_colind, CRS_vals);
611}
612
613template<typename rowptr_array_type, typename colind_array_type>
614void
615sortCrsEntries (const rowptr_array_type& CRS_rowptr,
616 const colind_array_type& CRS_colind)
617{
618 // Generate dummy values array
619 typedef typename colind_array_type::execution_space execution_space;
620 typedef Tpetra::Details::DefaultTypes::scalar_type scalar_type;
621 typedef typename Kokkos::View<scalar_type*, execution_space> scalar_view_type;
622 scalar_view_type CRS_vals;
623 sortCrsEntries<rowptr_array_type, colind_array_type,
624 scalar_view_type>(CRS_rowptr, CRS_colind, CRS_vals);
625}
626
627// Note: This should get merged with the other Tpetra sort routines eventually.
628template<typename Scalar, typename Ordinal>
629void
630sortAndMergeCrsEntries (const Teuchos::ArrayView<size_t> &CRS_rowptr,
631 const Teuchos::ArrayView<Ordinal> & CRS_colind,
632 const Teuchos::ArrayView<Scalar> &CRS_vals)
633{
634 // For each row, sort column entries from smallest to largest,
635 // merging column ids that are identify by adding values. Use shell
636 // sort. Stable sort so it is fast if indices are already sorted.
637 // Code copied from Epetra_CrsMatrix::SortEntries()
638
639 if (CRS_rowptr.size () == 0) {
640 return; // no rows, so nothing to sort
641 }
642 const size_t NumRows = CRS_rowptr.size () - 1;
643 const size_t nnz = CRS_colind.size ();
644 size_t new_curr = CRS_rowptr[0];
645 size_t old_curr = CRS_rowptr[0];
646
647 const bool permute_values_array = CRS_vals.size() > 0;
648
649 for(size_t i = 0; i < NumRows; i++){
650 const size_t old_rowptr_i=CRS_rowptr[i];
651 CRS_rowptr[i] = old_curr;
652 if(old_rowptr_i >= nnz) continue;
653
654 size_t NumEntries = CRS_rowptr[i+1] - old_rowptr_i;
655 Teuchos::ArrayRCP<Scalar> locValues;
656 if (permute_values_array)
657 locValues = Teuchos::arcp<Scalar>(&CRS_vals[old_rowptr_i], 0, NumEntries, false);
658 Teuchos::ArrayRCP<Ordinal> locIndices(&CRS_colind[old_rowptr_i], 0, NumEntries, false);
659
660 // Sort phase
661 Ordinal n = NumEntries;
662 Ordinal m = n/2;
663
664 while(m > 0) {
665 Ordinal max = n - m;
666 for(Ordinal j = 0; j < max; j++) {
667 for(Ordinal k = j; k >= 0; k-=m) {
668 if(locIndices[k+m] >= locIndices[k])
669 break;
670 if (permute_values_array) {
671 Scalar dtemp = locValues[k+m];
672 locValues[k+m] = locValues[k];
673 locValues[k] = dtemp;
674 }
675 Ordinal itemp = locIndices[k+m];
676 locIndices[k+m] = locIndices[k];
677 locIndices[k] = itemp;
678 }
679 }
680 m = m/2;
681 }
682
683 // Merge & shrink
684 for(size_t j=old_rowptr_i; j < CRS_rowptr[i+1]; j++) {
685 if(j > old_rowptr_i && CRS_colind[j]==CRS_colind[new_curr-1]) {
686 if (permute_values_array) CRS_vals[new_curr-1] += CRS_vals[j];
687 }
688 else if(new_curr==j) {
689 new_curr++;
690 }
691 else {
692 CRS_colind[new_curr] = CRS_colind[j];
693 if (permute_values_array) CRS_vals[new_curr] = CRS_vals[j];
694 new_curr++;
695 }
696 }
697 old_curr=new_curr;
698 }
699
700 CRS_rowptr[NumRows] = new_curr;
701}
702
703template<typename Ordinal>
704void
705sortAndMergeCrsEntries (const Teuchos::ArrayView<size_t> &CRS_rowptr,
706 const Teuchos::ArrayView<Ordinal> & CRS_colind)
707{
708 Teuchos::ArrayView<Tpetra::Details::DefaultTypes::scalar_type> CRS_vals;
709 return sortAndMergeCrsEntries(CRS_rowptr, CRS_colind, CRS_vals);
710}
711
712
713template <typename LocalOrdinal, typename GlobalOrdinal, typename Node>
714void
715lowCommunicationMakeColMapAndReindex (const Teuchos::ArrayView<const size_t> &rowptr,
716 const Teuchos::ArrayView<LocalOrdinal> &colind_LID,
717 const Teuchos::ArrayView<GlobalOrdinal> &colind_GID,
718 const Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >& domainMapRCP,
719 const Teuchos::ArrayView<const int> &owningPIDs,
720 Teuchos::Array<int> &remotePIDs,
721 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > & colMap)
722{
723 using Teuchos::rcp;
724 typedef LocalOrdinal LO;
725 typedef GlobalOrdinal GO;
726 typedef Tpetra::global_size_t GST;
728 const char prefix[] = "lowCommunicationMakeColMapAndReindex: ";
729
730 // The domainMap is an RCP because there is a shortcut for a
731 // (common) special case to return the columnMap = domainMap.
732 const map_type& domainMap = *domainMapRCP;
733
734 // Scan all column indices and sort into two groups:
735 // Local: those whose GID matches a GID of the domain map on this processor and
736 // Remote: All others.
737 const size_t numDomainElements = domainMap.getLocalNumElements ();
738 Teuchos::Array<bool> LocalGIDs;
739 if (numDomainElements > 0) {
740 LocalGIDs.resize (numDomainElements, false); // Assume domain GIDs are not local
741 }
742
743 // In principle it is good to have RemoteGIDs and RemotGIDList be as
744 // long as the number of remote GIDs on this processor, but this
745 // would require two passes through the column IDs, so we make it
746 // the max of 100 and the number of block rows.
747 //
748 // FIXME (mfh 11 Feb 2015) Tpetra::Details::HashTable can hold at
749 // most INT_MAX entries, but it's possible to have more rows than
750 // that (if size_t is 64 bits and int is 32 bits).
751 const size_t numMyRows = rowptr.size () - 1;
752 const int hashsize = std::max (static_cast<int> (numMyRows), 100);
753
754 Tpetra::Details::HashTable<GO, LO> RemoteGIDs (hashsize);
755 Teuchos::Array<GO> RemoteGIDList;
756 RemoteGIDList.reserve (hashsize);
757 Teuchos::Array<int> PIDList;
758 PIDList.reserve (hashsize);
759
760 // Here we start using the *LocalOrdinal* colind_LID array. This is
761 // safe even if both columnIndices arrays are actually the same
762 // (because LocalOrdinal==GO). For *local* GID's set
763 // colind_LID with with their LID in the domainMap. For *remote*
764 // GIDs, we set colind_LID with (numDomainElements+NumRemoteColGIDs)
765 // before the increment of the remote count. These numberings will
766 // be separate because no local LID is greater than
767 // numDomainElements.
768
769 size_t NumLocalColGIDs = 0;
770 LO NumRemoteColGIDs = 0;
771 for (size_t i = 0; i < numMyRows; ++i) {
772 for(size_t j = rowptr[i]; j < rowptr[i+1]; ++j) {
773 const GO GID = colind_GID[j];
774 // Check if GID matches a row GID
775 const LO LID = domainMap.getLocalElement (GID);
776 if(LID != -1) {
777 const bool alreadyFound = LocalGIDs[LID];
778 if (! alreadyFound) {
779 LocalGIDs[LID] = true; // There is a column in the graph associated with this domain map GID
780 NumLocalColGIDs++;
781 }
782 colind_LID[j] = LID;
783 }
784 else {
785 const LO hash_value = RemoteGIDs.get (GID);
786 if (hash_value == -1) { // This means its a new remote GID
787 const int PID = owningPIDs[j];
788 TEUCHOS_TEST_FOR_EXCEPTION(
789 PID == -1, std::invalid_argument, prefix << "Cannot figure out if "
790 "PID is owned.");
791 colind_LID[j] = static_cast<LO> (numDomainElements + NumRemoteColGIDs);
792 RemoteGIDs.add (GID, NumRemoteColGIDs);
793 RemoteGIDList.push_back (GID);
794 PIDList.push_back (PID);
795 NumRemoteColGIDs++;
796 }
797 else {
798 colind_LID[j] = static_cast<LO> (numDomainElements + hash_value);
799 }
800 }
801 }
802 }
803
804 // Possible short-circuit: If all domain map GIDs are present as
805 // column indices, then set ColMap=domainMap and quit.
806 if (domainMap.getComm ()->getSize () == 1) {
807 // Sanity check: When there is only one process, there can be no
808 // remoteGIDs.
809 TEUCHOS_TEST_FOR_EXCEPTION(
810 NumRemoteColGIDs != 0, std::runtime_error, prefix << "There is only one "
811 "process in the domain Map's communicator, which means that there are no "
812 "\"remote\" indices. Nevertheless, some column indices are not in the "
813 "domain Map.");
814 if (static_cast<size_t> (NumLocalColGIDs) == numDomainElements) {
815 // In this case, we just use the domainMap's indices, which is,
816 // not coincidently, what we clobbered colind with up above
817 // anyway. No further reindexing is needed.
818 colMap = domainMapRCP;
819 return;
820 }
821 }
822
823 // Now build the array containing column GIDs
824 // Build back end, containing remote GIDs, first
825 const LO numMyCols = NumLocalColGIDs + NumRemoteColGIDs;
826 Teuchos::Array<GO> ColIndices;
827 GO* RemoteColIndices = NULL;
828 if (numMyCols > 0) {
829 ColIndices.resize (numMyCols);
830 if (NumLocalColGIDs != static_cast<size_t> (numMyCols)) {
831 RemoteColIndices = &ColIndices[NumLocalColGIDs]; // Points to back half of ColIndices
832 }
833 }
834
835 for (LO i = 0; i < NumRemoteColGIDs; ++i) {
836 RemoteColIndices[i] = RemoteGIDList[i];
837 }
838
839 // Build permute array for *remote* reindexing.
840 Teuchos::Array<LO> RemotePermuteIDs (NumRemoteColGIDs);
841 for (LO i = 0; i < NumRemoteColGIDs; ++i) {
842 RemotePermuteIDs[i]=i;
843 }
844
845 // Sort External column indices so that all columns coming from a
846 // given remote processor are contiguous. This is a sort with two
847 // auxilary arrays: RemoteColIndices and RemotePermuteIDs.
848 Tpetra::sort3 (PIDList.begin (), PIDList.end (),
849 ColIndices.begin () + NumLocalColGIDs,
850 RemotePermuteIDs.begin ());
851
852 // Stash the RemotePIDs.
853 //
854 // Note: If Teuchos::Array had a shrink_to_fit like std::vector,
855 // we'd call it here.
856 remotePIDs = PIDList;
857
858 // Sort external column indices so that columns from a given remote
859 // processor are not only contiguous but also in ascending
860 // order. NOTE: I don't know if the number of externals associated
861 // with a given remote processor is known at this point ... so I
862 // count them here.
863
864 // NTS: Only sort the RemoteColIndices this time...
865 LO StartCurrent = 0, StartNext = 1;
866 while (StartNext < NumRemoteColGIDs) {
867 if (PIDList[StartNext]==PIDList[StartNext-1]) {
868 StartNext++;
869 }
870 else {
871 Tpetra::sort2 (ColIndices.begin () + NumLocalColGIDs + StartCurrent,
872 ColIndices.begin () + NumLocalColGIDs + StartNext,
873 RemotePermuteIDs.begin () + StartCurrent);
874 StartCurrent = StartNext;
875 StartNext++;
876 }
877 }
878 Tpetra::sort2 (ColIndices.begin () + NumLocalColGIDs + StartCurrent,
879 ColIndices.begin () + NumLocalColGIDs + StartNext,
880 RemotePermuteIDs.begin () + StartCurrent);
881
882 // Reverse the permutation to get the information we actually care about
883 Teuchos::Array<LO> ReverseRemotePermuteIDs (NumRemoteColGIDs);
884 for (LO i = 0; i < NumRemoteColGIDs; ++i) {
885 ReverseRemotePermuteIDs[RemotePermuteIDs[i]] = i;
886 }
887
888 // Build permute array for *local* reindexing.
889 bool use_local_permute = false;
890 Teuchos::Array<LO> LocalPermuteIDs (numDomainElements);
891
892 // Now fill front end. Two cases:
893 //
894 // (1) If the number of Local column GIDs is the same as the number
895 // of Local domain GIDs, we can simply read the domain GIDs into
896 // the front part of ColIndices, otherwise
897 //
898 // (2) We step through the GIDs of the domainMap, checking to see if
899 // each domain GID is a column GID. we want to do this to
900 // maintain a consistent ordering of GIDs between the columns
901 // and the domain.
902 Teuchos::ArrayView<const GO> domainGlobalElements = domainMap.getLocalElementList();
903 if (static_cast<size_t> (NumLocalColGIDs) == numDomainElements) {
904 if (NumLocalColGIDs > 0) {
905 // Load Global Indices into first numMyCols elements column GID list
906 std::copy (domainGlobalElements.begin (), domainGlobalElements.end (),
907 ColIndices.begin ());
908 }
909 }
910 else {
911 LO NumLocalAgain = 0;
912 use_local_permute = true;
913 for (size_t i = 0; i < numDomainElements; ++i) {
914 if (LocalGIDs[i]) {
915 LocalPermuteIDs[i] = NumLocalAgain;
916 ColIndices[NumLocalAgain++] = domainGlobalElements[i];
917 }
918 }
919 TEUCHOS_TEST_FOR_EXCEPTION(
920 static_cast<size_t> (NumLocalAgain) != NumLocalColGIDs,
921 std::runtime_error, prefix << "Local ID count test failed.");
922 }
923
924 // Make column Map
925 const GST minus_one = Teuchos::OrdinalTraits<GST>::invalid ();
926 colMap = rcp (new map_type (minus_one, ColIndices, domainMap.getIndexBase (),
927 domainMap.getComm ()));
928
929 // Low-cost reindex of the matrix
930 for (size_t i = 0; i < numMyRows; ++i) {
931 for (size_t j = rowptr[i]; j < rowptr[i+1]; ++j) {
932 const LO ID = colind_LID[j];
933 if (static_cast<size_t> (ID) < numDomainElements) {
934 if (use_local_permute) {
935 colind_LID[j] = LocalPermuteIDs[colind_LID[j]];
936 }
937 // In the case where use_local_permute==false, we just copy
938 // the DomainMap's ordering, which it so happens is what we
939 // put in colind_LID to begin with.
940 }
941 else {
942 colind_LID[j] = NumLocalColGIDs + ReverseRemotePermuteIDs[colind_LID[j]-numDomainElements];
943 }
944 }
945 }
946}
947
948
949
950
951// Generates an list of owning PIDs based on two transfer (aka import/export objects)
952// Let:
953// OwningMap = useReverseModeForOwnership ? transferThatDefinesOwnership.getTargetMap() : transferThatDefinesOwnership.getSourceMap();
954// MapAo = useReverseModeForOwnership ? transferThatDefinesOwnership.getSourceMap() : transferThatDefinesOwnership.getTargetMap();
955// MapAm = useReverseModeForMigration ? transferThatDefinesMigration.getTargetMap() : transferThatDefinesMigration.getSourceMap();
956// VectorMap = useReverseModeForMigration ? transferThatDefinesMigration.getSourceMap() : transferThatDefinesMigration.getTargetMap();
957// Precondition:
958// 1) MapAo.isSameAs(*MapAm) - map compatibility between transfers
959// 2) VectorMap->isSameAs(*owningPIDs->getMap()) - map compabibility between transfer & vector
960// 3) OwningMap->isOneToOne() - owning map is 1-to-1
961// --- Precondition 3 is only checked in DEBUG mode ---
962// Postcondition:
963// owningPIDs[VectorMap->getLocalElement(GID i)] = j iff (OwningMap->isLocalElement(GID i) on rank j)
964template <typename LocalOrdinal, typename GlobalOrdinal, typename Node>
965void getTwoTransferOwnershipVector(const ::Tpetra::Details::Transfer<LocalOrdinal, GlobalOrdinal, Node>& transferThatDefinesOwnership,
966 bool useReverseModeForOwnership,
967 const ::Tpetra::Details::Transfer<LocalOrdinal, GlobalOrdinal, Node>& transferThatDefinesMigration,
968 bool useReverseModeForMigration,
972
973 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > OwningMap = useReverseModeForOwnership ?
974 transferThatDefinesOwnership.getTargetMap() :
975 transferThatDefinesOwnership.getSourceMap();
976 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > MapAo = useReverseModeForOwnership ?
977 transferThatDefinesOwnership.getSourceMap() :
978 transferThatDefinesOwnership.getTargetMap();
979 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > MapAm = useReverseModeForMigration ?
980 transferThatDefinesMigration.getTargetMap() :
981 transferThatDefinesMigration.getSourceMap();
982 Teuchos::RCP<const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> > VectorMap = useReverseModeForMigration ?
983 transferThatDefinesMigration.getSourceMap() :
984 transferThatDefinesMigration.getTargetMap();
985
986 TEUCHOS_TEST_FOR_EXCEPTION(!MapAo->isSameAs(*MapAm),std::runtime_error,"Tpetra::Import_Util::getTwoTransferOwnershipVector map mismatch between transfers");
987 TEUCHOS_TEST_FOR_EXCEPTION(!VectorMap->isSameAs(*owningPIDs.getMap()),std::runtime_error,"Tpetra::Import_Util::getTwoTransferOwnershipVector map mismatch transfer and vector");
988#ifdef HAVE_TPETRA_DEBUG
989 TEUCHOS_TEST_FOR_EXCEPTION(!OwningMap->isOneToOne(),std::runtime_error,"Tpetra::Import_Util::getTwoTransferOwnershipVector owner must be 1-to-1");
990#endif
991
992 int rank = OwningMap->getComm()->getRank();
993 // Generate "A" vector and fill it with owning information. We can read this from transferThatDefinesOwnership w/o communication
994 // Note: Due to the 1-to-1 requirement, several of these options throw
996 const import_type* ownAsImport = dynamic_cast<const import_type*> (&transferThatDefinesOwnership);
997 const export_type* ownAsExport = dynamic_cast<const export_type*> (&transferThatDefinesOwnership);
998
999 Teuchos::ArrayRCP<int> pids = temp.getDataNonConst();
1000 Teuchos::ArrayView<int> v_pids = pids();
1001 if(ownAsImport && useReverseModeForOwnership) {TEUCHOS_TEST_FOR_EXCEPTION(1,std::runtime_error,"Tpetra::Import_Util::getTwoTransferOwnershipVector owner must be 1-to-1");}
1002 else if(ownAsImport && !useReverseModeForOwnership) getPids(*ownAsImport,v_pids,false);
1003 else if(ownAsExport && useReverseModeForMigration) {TEUCHOS_TEST_FOR_EXCEPTION(1,std::runtime_error,"Tpetra::Import_Util::getTwoTransferOwnershipVector this option not yet implemented");}
1004 else {TEUCHOS_TEST_FOR_EXCEPTION(1,std::runtime_error,"Tpetra::Import_Util::getTwoTransferOwnershipVector owner must be 1-to-1");}
1005
1006 const import_type* xferAsImport = dynamic_cast<const import_type*> (&transferThatDefinesMigration);
1007 const export_type* xferAsExport = dynamic_cast<const export_type*> (&transferThatDefinesMigration);
1008 TEUCHOS_TEST_FOR_EXCEPTION(!xferAsImport && !xferAsExport,std::runtime_error,"Tpetra::Import_Util::getTwoTransferOwnershipVector transfer undefined");
1009
1010 // Migrate from "A" vector to output vector
1011 owningPIDs.putScalar(rank);
1012 if(xferAsImport && useReverseModeForMigration) owningPIDs.doExport(temp,*xferAsImport,Tpetra::REPLACE);
1013 else if(xferAsImport && !useReverseModeForMigration) owningPIDs.doImport(temp,*xferAsImport,Tpetra::REPLACE);
1014 else if(xferAsExport && useReverseModeForMigration) owningPIDs.doImport(temp,*xferAsExport,Tpetra::REPLACE);
1015 else owningPIDs.doExport(temp,*xferAsExport,Tpetra::REPLACE);
1016
1017}
1018
1019
1020
1021} // namespace Import_Util
1022} // namespace Tpetra
1023
1024#endif // TPETRA_IMPORT_UTIL_HPP
Declaration of the Tpetra::CrsMatrix class.
Add specializations of Teuchos::Details::MpiTypeTraits for Kokkos::complex<float> and Kokkos::complex...
Declaration and definition of Tpetra::Details::reallocDualViewIfNeeded, an implementation detail of T...
void lowCommunicationMakeColMapAndReindex(const Teuchos::ArrayView< const size_t > &rowPointers, const Teuchos::ArrayView< LocalOrdinal > &columnIndices_LID, const Teuchos::ArrayView< GlobalOrdinal > &columnIndices_GID, const Teuchos::RCP< const Tpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > &domainMap, const Teuchos::ArrayView< const int > &owningPids, Teuchos::Array< int > &remotePids, Teuchos::RCP< const Tpetra::Map< LocalOrdinal, GlobalOrdinal, Node > > &colMap)
lowCommunicationMakeColMapAndReindex
void getTwoTransferOwnershipVector(const ::Tpetra::Details::Transfer< LocalOrdinal, GlobalOrdinal, Node > &transferThatDefinesOwnership, bool useReverseModeForOwnership, const ::Tpetra::Details::Transfer< LocalOrdinal, GlobalOrdinal, Node > &transferForMigratingData, bool useReverseModeForMigration, Tpetra::Vector< int, LocalOrdinal, GlobalOrdinal, Node > &owningPIDs)
Generates an list of owning PIDs based on two transfer (aka import/export objects) Let: OwningMap = u...
void sortAndMergeCrsEntries(const Teuchos::ArrayView< size_t > &CRS_rowptr, const Teuchos::ArrayView< Ordinal > &CRS_colind, const Teuchos::ArrayView< Scalar > &CRS_vals)
Sort and merge the entries of the (raw CSR) matrix by column index within each row.
void sortCrsEntries(const Teuchos::ArrayView< size_t > &CRS_rowptr, const Teuchos::ArrayView< Ordinal > &CRS_colind, const Teuchos::ArrayView< Scalar > &CRS_vals)
Sort the entries of the (raw CSR) matrix by column index within each row.
void getPids(const Tpetra::Import< LocalOrdinal, GlobalOrdinal, Node > &Importer, Teuchos::Array< int > &pids, bool use_minus_one_for_local)
Like getPidGidPairs, but just gets the PIDs, ordered by the column Map.
Stand-alone utility functions and macros.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
The communicator over which the matrix is distributed.
GlobalOrdinal getIndexBase() const override
The index base for global indices for this matrix.
ValueType get(const KeyType key)
Get the value corresponding to the given key.
void add(const KeyType key, const ValueType value)
Add a key and its value to the hash table.
Teuchos::ArrayView< const LO > getExportLIDs() const
List of entries in the source Map that will be sent to other processes.
size_t getNumExportIDs() const
Number of entries that must be sent by the calling process to other processes.
Teuchos::ArrayView< const int > getExportPIDs() const
List of processes to which entries will be sent.
void doImport(const SrcDistObject &source, const Import< LocalOrdinal, GlobalOrdinal, Node > &importer, const CombineMode CM, const bool restrictedMode=false)
Import data into this object using an Import object ("forward mode").
void doExport(const SrcDistObject &source, const Export< LocalOrdinal, GlobalOrdinal, Node > &exporter, const CombineMode CM, const bool restrictedMode=false)
Export data into this object using an Export object ("forward mode").
virtual Teuchos::RCP< const map_type > getMap() const
The Map describing the parallel distribution of this object.
Communication plan for data redistribution from a (possibly) multiply-owned to a uniquely-owned distr...
Communication plan for data redistribution from a uniquely-owned to a (possibly) multiply-owned distr...
A parallel distribution of indices over processes.
void putScalar(const Scalar &value)
Set all values in the multivector with the given value.
A distributed dense vector.
Teuchos::ArrayRCP< Scalar > getDataNonConst()
View of the local values of this vector.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
void sort3(const IT1 &first1, const IT1 &last1, const IT2 &first2, const IT3 &first3)
Sort the first array, and apply the same permutation to the second and third arrays.
void sort2(const IT1 &first1, const IT1 &last1, const IT2 &first2)
Sort the first array, and apply the resulting permutation to the second array.
size_t global_size_t
Global size_t object.
@ REPLACE
Replace existing values with new values.