Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_Details_unpackCrsMatrixAndCombine_def.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Tpetra: Templated Linear Algebra Services Package
4//
5// Copyright 2008 NTESS and the Tpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef TPETRA_DETAILS_UNPACKCRSMATRIXANDCOMBINE_DEF_HPP
11#define TPETRA_DETAILS_UNPACKCRSMATRIXANDCOMBINE_DEF_HPP
12
13#include <memory>
14#include <string>
15#include "TpetraCore_config.h"
16#include "Kokkos_Core.hpp"
17#include "Teuchos_Array.hpp"
18#include "Teuchos_ArrayView.hpp"
19#include "Teuchos_OrdinalTraits.hpp"
20#include "Teuchos_TimeMonitor.hpp"
28#include "Tpetra_Details_DefaultTypes.hpp"
30
51
52namespace Tpetra {
53
54//
55// Users must never rely on anything in the Details namespace.
56//
57namespace Details {
58
59namespace UnpackAndCombineCrsMatrixImpl {
60
70template <class ST, class LO, class GO>
71KOKKOS_FUNCTION int
73 const typename PackTraits<int>::output_array_type& pids_out,
74 const typename PackTraits<ST>::output_array_type& vals_out,
75 const char imports[],
76 const size_t offset,
77 const size_t num_bytes,
78 const size_t num_ent,
79 const size_t bytes_per_value) {
80 if (num_ent == 0) {
81 // Empty rows always take zero bytes, to ensure sparsity.
82 return 0;
83 }
84 bool unpack_pids = pids_out.size() > 0;
85
86 const size_t num_ent_beg = offset;
87 const size_t num_ent_len = PackTraits<LO>::packValueCount(LO(0));
88
89 const size_t gids_beg = num_ent_beg + num_ent_len;
90 const size_t gids_len =
91 num_ent * PackTraits<GO>::packValueCount(GO(0));
92
93 const size_t pids_beg = gids_beg + gids_len;
94 const size_t pids_len = unpack_pids ? size_t(num_ent * PackTraits<int>::packValueCount(int(0))) : size_t(0);
95
96 const size_t vals_beg = gids_beg + gids_len + pids_len;
97 const size_t vals_len = num_ent * bytes_per_value;
98
99 const size_t expected_num_bytes = num_ent_len + gids_len + pids_len + vals_len;
100 if (expected_num_bytes > num_bytes) {
101 return 25; // error code: insufficient bytes
102 }
103
104 const char* const num_ent_in = imports + num_ent_beg;
105 const char* const gids_in = imports + gids_beg;
106 const char* const pids_in = unpack_pids ? imports + pids_beg : nullptr;
107 const char* const vals_in = imports + vals_beg;
108
109 size_t num_bytes_out = 0;
110 LO num_ent_out;
111 num_bytes_out += PackTraits<LO>::unpackValue(num_ent_out, num_ent_in);
112 if (static_cast<size_t>(num_ent_out) != num_ent) {
113 return 20; // error code
114 }
115
116 {
117 Kokkos::pair<int, size_t> p;
118 p = PackTraits<GO>::unpackArray(gids_out.data(), gids_in, num_ent);
119 if (p.first != 0) {
120 return 21; // error code
121 }
122 num_bytes_out += p.second;
123
124 if (unpack_pids) {
125 p = PackTraits<int>::unpackArray(pids_out.data(), pids_in, num_ent);
126 if (p.first != 0) {
127 return 22; // error code
128 }
129 num_bytes_out += p.second;
130 }
131
132 p = PackTraits<ST>::unpackArray(vals_out.data(), vals_in, num_ent);
133 if (p.first != 0) {
134 return 23; // error code
135 }
136 num_bytes_out += p.second;
137 }
138
139 if (num_bytes_out != expected_num_bytes) {
140 return 24; // error code
141 }
142 return 0; // no errors
143} // unpackRow
144
155template <class LocalMatrix, class LocalMap, class BufferDeviceType>
156struct UnpackCrsMatrixAndCombineFunctor {
157 typedef LocalMatrix local_matrix_type;
158 typedef LocalMap local_map_type;
159
160 typedef typename local_matrix_type::value_type ST;
161 typedef typename local_map_type::local_ordinal_type LO;
162 typedef typename local_map_type::global_ordinal_type GO;
163 typedef typename local_map_type::device_type DT;
164 typedef typename DT::execution_space XS;
165
166 typedef Kokkos::View<const size_t*, BufferDeviceType>
167 num_packets_per_lid_type;
168 typedef Kokkos::View<const size_t*, DT> offsets_type;
169 typedef Kokkos::View<const char*, BufferDeviceType> input_buffer_type;
170 typedef Kokkos::View<const LO*, BufferDeviceType> import_lids_type;
171
172 typedef Kokkos::View<int, DT> error_type;
173 using member_type = typename Kokkos::TeamPolicy<XS>::member_type;
174
175 static_assert(std::is_same<LO, typename local_matrix_type::ordinal_type>::value,
176 "LocalMap::local_ordinal_type and "
177 "LocalMatrix::ordinal_type must be the same.");
178
179 local_matrix_type local_matrix;
180 local_map_type local_col_map;
181 input_buffer_type imports;
182 num_packets_per_lid_type num_packets_per_lid;
183 import_lids_type import_lids;
184 Kokkos::View<const LO* [2], DT> batch_info;
185 offsets_type offsets;
186 Tpetra::CombineMode combine_mode;
187 size_t batch_size;
188 size_t bytes_per_value;
189 bool atomic;
190 error_type error_code;
191
192 UnpackCrsMatrixAndCombineFunctor(
193 const local_matrix_type& local_matrix_in,
194 const local_map_type& local_col_map_in,
195 const input_buffer_type& imports_in,
196 const num_packets_per_lid_type& num_packets_per_lid_in,
197 const import_lids_type& import_lids_in,
198 const Kokkos::View<const LO* [2], DT>& batch_info_in,
199 const offsets_type& offsets_in,
200 const Tpetra::CombineMode combine_mode_in,
201 const size_t batch_size_in,
202 const size_t bytes_per_value_in,
203 const bool atomic_in)
204 : local_matrix(local_matrix_in)
205 , local_col_map(local_col_map_in)
206 , imports(imports_in)
207 , num_packets_per_lid(num_packets_per_lid_in)
208 , import_lids(import_lids_in)
209 , batch_info(batch_info_in)
210 , offsets(offsets_in)
211 , combine_mode(combine_mode_in)
212 , batch_size(batch_size_in)
213 , bytes_per_value(bytes_per_value_in)
214 , atomic(atomic_in)
215 , error_code("error") {}
216
217 KOKKOS_INLINE_FUNCTION
218 void operator()(member_type team_member) const {
219 using Kokkos::MemoryUnmanaged;
220 using Kokkos::subview;
221 using Kokkos::View;
222
223 const LO batch = team_member.league_rank();
224 const LO lid_no = batch_info(batch, 0);
225 const LO batch_no = batch_info(batch, 1);
226
227 const size_t num_bytes = num_packets_per_lid(lid_no);
228
229 // Only unpack data if there is a nonzero number of bytes.
230 if (num_bytes == 0)
231 return;
232
233 // there is actually something in the row
234 const LO import_lid = import_lids(lid_no);
235 const size_t buf_size = imports.size();
236 const size_t offset = offsets(lid_no);
237
238 // Get the number of entries to expect in the received data for this row.
239 LO num_ent_LO = 0;
240 const char* const in_buf = imports.data() + offset;
241 (void)PackTraits<LO>::unpackValue(num_ent_LO, in_buf);
242 const size_t num_entries_in_row = static_cast<size_t>(num_ent_LO);
243
244 // Count the number of bytes expected to unpack
245 size_t expected_num_bytes = 0;
246 {
247 expected_num_bytes += PackTraits<LO>::packValueCount(LO(0));
248 expected_num_bytes += num_entries_in_row * PackTraits<GO>::packValueCount(GO(0));
249 expected_num_bytes += num_entries_in_row * PackTraits<ST>::packValueCount(ST());
250 }
251
252 if (expected_num_bytes > num_bytes) {
253 Kokkos::printf(
254 "*** Error: UnpackCrsMatrixAndCombineFunctor: "
255 "At row %d, the expected number of bytes (%d) != number of unpacked bytes (%d)\n",
256 (int)lid_no, (int)expected_num_bytes, (int)num_bytes);
257
258 Kokkos::atomic_compare_exchange(error_code.data(), 0, 21);
259 return;
260 }
261
262 if (offset > buf_size || offset + num_bytes > buf_size) {
263 Kokkos::printf(
264 "*** Error: UnpackCrsMatrixAndCombineFunctor: "
265 "At row %d, the offset (%d) > buffer size (%d)\n",
266 (int)lid_no, (int)offset, (int)buf_size);
267
268 Kokkos::atomic_compare_exchange(error_code.data(), 0, 22);
269 return;
270 }
271
272 // Determine the number of entries to unpack in this batch
273 size_t num_entries_in_batch = 0;
274 if (num_entries_in_row <= batch_size)
275 num_entries_in_batch = num_entries_in_row;
276 else if (num_entries_in_row >= (batch_no + 1) * batch_size)
277 num_entries_in_batch = batch_size;
278 else
279 num_entries_in_batch = num_entries_in_row - batch_no * batch_size;
280
281 const size_t bytes_per_lid = PackTraits<LO>::packValueCount(LO(0));
282 const size_t num_ent_start = offset;
283 const size_t num_ent_end = num_ent_start + bytes_per_lid;
284
285 const size_t bytes_per_gid = PackTraits<GO>::packValueCount(GO(0));
286 const size_t gids_start = num_ent_end;
287 const size_t gids_end = gids_start + num_entries_in_row * bytes_per_gid;
288
289 const size_t vals_start = gids_end;
290
291 const size_t shift = batch_no * batch_size;
292 const char* const num_ent_in = imports.data() + num_ent_start;
293 const char* const gids_in = imports.data() + gids_start + shift * bytes_per_gid;
294 const char* const vals_in = imports.data() + vals_start + shift * bytes_per_value;
295
296 LO num_ent_out;
297 (void)PackTraits<LO>::unpackValue(num_ent_out, num_ent_in);
298 if (static_cast<size_t>(num_ent_out) != num_entries_in_row) {
299 Kokkos::printf(
300 "*** Error: UnpackCrsMatrixAndCombineFunctor: "
301 "At row %d, number of entries (%d) != number of entries unpacked (%d)\n",
302 (int)lid_no, (int)num_entries_in_row, (int)num_ent_out);
303
304 Kokkos::atomic_compare_exchange(error_code.data(), 0, 23);
305 }
306
307 constexpr bool matrix_has_sorted_rows = true; // see #6282
308 // Note BMK 6-22: this lambda must use capture-by-value [=] and not capture-by-ref [&].
309 // By ref triggers compiler bug in CUDA 10.
310 Kokkos::parallel_for(
311 Kokkos::TeamThreadRange(team_member, num_entries_in_batch),
312 [=, *this](const LO& j) {
313 size_t distance = 0;
314
315 GO gid_out;
316 distance = j * bytes_per_gid;
317 (void)PackTraits<GO>::unpackValue(gid_out, gids_in + distance);
318 auto lid_out = local_col_map.getLocalElement(gid_out);
319
320 // Column indices come in as global indices, in case the
321 // source object's column Map differs from the target object's
322 // (this's) column Map, and must be converted local index values
323
324 // assume that ST is default constructible
325 ST val_out;
326 distance = j * bytes_per_value;
327 (void)PackTraits<ST>::unpackValue(val_out, vals_in + distance);
328
329 if (combine_mode == ADD) {
330 // NOTE (mfh 20 Nov 2019) Must assume atomic is required, unless
331 // different threads don't touch the same row (i.e., no
332 // duplicates in incoming LIDs list).
333 const bool use_atomic_updates = atomic;
334 (void)local_matrix.sumIntoValues(
335 import_lid,
336 &lid_out,
337 1,
338 &val_out,
339 matrix_has_sorted_rows,
340 use_atomic_updates);
341 } else if (combine_mode == REPLACE) {
342 // NOTE (mfh 20 Nov 2019): It's never correct to use REPLACE
343 // combine mode with multiple incoming rows that touch the same
344 // target matrix entries, so we never need atomic updates.
345 const bool use_atomic_updates = false;
346 (void)local_matrix.replaceValues(
347 import_lid,
348 &lid_out,
349 1,
350 &val_out,
351 matrix_has_sorted_rows,
352 use_atomic_updates);
353 } else {
354 // should never get here
355 Kokkos::printf(
356 "*** Error: UnpackCrsMatrixAndCombineFunctor: "
357 "At row %d, an unknown error occurred during unpack\n",
358 (int)lid_no);
359 Kokkos::atomic_compare_exchange(error_code.data(), 0, 31);
360 }
361 });
362
363 team_member.team_barrier();
364 }
365
367 int error() const {
368 auto error_code_h = Kokkos::create_mirror_view_and_copy(
369 Kokkos::HostSpace(), error_code);
370 return error_code_h();
371 }
372
373}; // UnpackCrsMatrixAndCombineFunctor
374
375struct MaxNumEntTag {};
376struct TotNumEntTag {};
377
386template <class LO, class DT, class BDT>
387class NumEntriesFunctor {
388 public:
389 typedef Kokkos::View<const size_t*, BDT> num_packets_per_lid_type;
390 typedef Kokkos::View<const size_t*, DT> offsets_type;
391 typedef Kokkos::View<const char*, BDT> input_buffer_type;
392 // This needs to be public, since it appears in the argument list of
393 // public methods (see below). Otherwise, build errors may happen.
394 typedef size_t value_type;
395
396 private:
397 num_packets_per_lid_type num_packets_per_lid;
398 offsets_type offsets;
399 input_buffer_type imports;
400
401 public:
402 NumEntriesFunctor(const num_packets_per_lid_type num_packets_per_lid_in,
403 const offsets_type& offsets_in,
404 const input_buffer_type& imports_in)
405 : num_packets_per_lid(num_packets_per_lid_in)
406 , offsets(offsets_in)
407 , imports(imports_in) {}
408
409 KOKKOS_INLINE_FUNCTION void
410 operator()(const MaxNumEntTag, const LO i, value_type& update) const {
411 // Get how many entries to expect in the received data for this row.
412 const size_t num_bytes = num_packets_per_lid(i);
413 if (num_bytes > 0) {
414 LO num_ent_LO = 0; // output argument of unpackValue
415 const char* const in_buf = imports.data() + offsets(i);
416 (void)PackTraits<LO>::unpackValue(num_ent_LO, in_buf);
417 const size_t num_ent = static_cast<size_t>(num_ent_LO);
418
419 update = (update < num_ent) ? num_ent : update;
420 }
421 }
422
423 KOKKOS_INLINE_FUNCTION void
424 join(const MaxNumEntTag,
425 value_type& dst,
426 const value_type& src) const {
427 if (dst < src) dst = src;
428 }
429
430 KOKKOS_INLINE_FUNCTION void
431 operator()(const TotNumEntTag, const LO i, value_type& tot_num_ent) const {
432 // Get how many entries to expect in the received data for this row.
433 const size_t num_bytes = num_packets_per_lid(i);
434 if (num_bytes > 0) {
435 LO num_ent_LO = 0; // output argument of unpackValue
436 const char* const in_buf = imports.data() + offsets(i);
437 (void)PackTraits<LO>::unpackValue(num_ent_LO, in_buf);
438 tot_num_ent += static_cast<size_t>(num_ent_LO);
439 }
440 }
441}; // NumEntriesFunctor
442
450template <class LO, class DT, class BDT>
451size_t
453 const Kokkos::View<const size_t*, BDT>& num_packets_per_lid,
454 const Kokkos::View<const size_t*, DT>& offsets,
455 const Kokkos::View<const char*, BDT>& imports) {
456 typedef typename DT::execution_space XS;
457 typedef Kokkos::RangePolicy<XS, Kokkos::IndexType<LO>,
458 MaxNumEntTag>
459 range_policy;
460
461 NumEntriesFunctor<LO, DT, BDT> functor(num_packets_per_lid, offsets,
462 imports);
463 const LO numRowsToUnpack =
464 static_cast<LO>(num_packets_per_lid.extent(0));
465 size_t max_num_ent = 0;
466 Kokkos::parallel_reduce("Max num entries in CRS",
467 range_policy(0, numRowsToUnpack),
468 functor, max_num_ent);
469 return max_num_ent;
470}
471
479template <class LO, class DT, class BDT>
480size_t
482 const Kokkos::View<const size_t*, BDT>& num_packets_per_lid,
483 const Kokkos::View<const size_t*, DT>& offsets,
484 const Kokkos::View<const char*, BDT>& imports) {
485 typedef typename DT::execution_space XS;
486 typedef Kokkos::RangePolicy<XS, Kokkos::IndexType<LO>, TotNumEntTag> range_policy;
487 size_t tot_num_ent = 0;
488 NumEntriesFunctor<LO, DT, BDT> functor(num_packets_per_lid, offsets,
489 imports);
490 const LO numRowsToUnpack =
491 static_cast<LO>(num_packets_per_lid.extent(0));
492 Kokkos::parallel_reduce("Total num entries in CRS to unpack",
493 range_policy(0, numRowsToUnpack),
494 functor, tot_num_ent);
495 return tot_num_ent;
496}
497
498template <class LO>
499KOKKOS_INLINE_FUNCTION
500 size_t
501 unpackRowCount(const char imports[],
502 const size_t offset,
503 const size_t num_bytes) {
504 using PT = PackTraits<LO>;
505
506 LO num_ent_LO = 0;
507 if (num_bytes > 0) {
508 const size_t p_num_bytes = PT::packValueCount(num_ent_LO);
509 if (p_num_bytes > num_bytes) {
510 return OrdinalTraits<size_t>::invalid();
511 }
512 const char* const in_buf = imports + offset;
513 (void)PT::unpackValue(num_ent_LO, in_buf);
514 }
515 return static_cast<size_t>(num_ent_LO);
516}
517
522template <class View1, class View2>
523inline bool
525 const View1& batches_per_lid,
526 View2& batch_info) {
527 using LO = typename View2::value_type;
528 size_t batch = 0;
529 for (size_t i = 0; i < batches_per_lid.extent(0); i++) {
530 for (size_t batch_no = 0; batch_no < batches_per_lid(i); batch_no++) {
531 batch_info(batch, 0) = static_cast<LO>(i);
532 batch_info(batch, 1) = batch_no;
533 batch++;
534 }
535 }
536 return batch == batch_info.extent(0);
537}
538
546template <class LocalMatrix, class LocalMap, class BufferDeviceType>
548 const LocalMatrix& local_matrix,
549 const LocalMap& local_map,
550 const Kokkos::View<const char*, BufferDeviceType>& imports,
551 const Kokkos::View<const size_t*, BufferDeviceType>& num_packets_per_lid,
553 const Tpetra::CombineMode combine_mode) {
554 using ST = typename LocalMatrix::value_type;
555 using LO = typename LocalMap::local_ordinal_type;
556 using DT = typename LocalMap::device_type;
557 using XS = typename DT::execution_space;
558 const char prefix[] =
559 "Tpetra::Details::UnpackAndCombineCrsMatrixImpl::"
560 "unpackAndCombineIntoCrsMatrix: ";
561
562 const size_t num_import_lids = static_cast<size_t>(import_lids.extent(0));
563 if (num_import_lids == 0) {
564 // Nothing to unpack
565 return;
566 }
567
568 {
569 // Check for correct input
570 TEUCHOS_TEST_FOR_EXCEPTION(combine_mode == ABSMAX,
571 std::invalid_argument,
572 prefix << "ABSMAX combine mode is not yet implemented for a matrix that has a "
573 "static graph (i.e., was constructed with the CrsMatrix constructor "
574 "that takes a const CrsGraph pointer).");
575
576 TEUCHOS_TEST_FOR_EXCEPTION(combine_mode == INSERT,
577 std::invalid_argument,
578 prefix << "INSERT combine mode is not allowed if the matrix has a static graph "
579 "(i.e., was constructed with the CrsMatrix constructor that takes a "
580 "const CrsGraph pointer).");
581
582 // Unknown combine mode!
583 TEUCHOS_TEST_FOR_EXCEPTION(!(combine_mode == ADD || combine_mode == REPLACE),
584 std::invalid_argument,
585 prefix << "Invalid combine mode; should never get "
586 "here! Please report this bug to the Tpetra developers.");
587
588 // Check that sizes of input objects are consistent.
589 bool bad_num_import_lids =
590 num_import_lids != static_cast<size_t>(num_packets_per_lid.extent(0));
591 TEUCHOS_TEST_FOR_EXCEPTION(bad_num_import_lids,
592 std::invalid_argument,
593 prefix << "importLIDs.size() (" << num_import_lids << ") != "
594 "numPacketsPerLID.size() ("
595 << num_packets_per_lid.extent(0) << ").");
596 } // end QA error checking
597
598 // Get the offsets
599 Kokkos::View<size_t*, DT> offsets("offsets", num_import_lids + 1);
600 computeOffsetsFromCounts(offsets, num_packets_per_lid);
601
602 // Determine the sizes of the unpack batches
603 size_t max_num_ent = compute_maximum_num_entries<LO, DT>(num_packets_per_lid, offsets, imports);
604 const size_t default_batch_size = Tpetra::Details::Behavior::hierarchicalUnpackBatchSize();
605 const size_t batch_size = std::min(default_batch_size, max_num_ent);
606
607 // To achieve some balance amongst threads, unpack each row in equal size batches
608 size_t num_batches = 0;
609 Kokkos::View<LO* [2], DT> batch_info("", num_batches);
610 Kokkos::View<size_t*, DT> batches_per_lid("", num_import_lids);
611 // Compute meta data that allows batch unpacking
612 Kokkos::parallel_reduce(
613 Kokkos::RangePolicy<XS, Kokkos::IndexType<size_t>>(0, num_import_lids),
614 KOKKOS_LAMBDA(const size_t i, size_t& batches) {
615 const size_t num_entries_in_row = unpackRowCount<LO>(
616 imports.data(), offsets(i), num_packets_per_lid(i));
617 batches_per_lid(i) =
618 (num_entries_in_row <= batch_size) ? 1 : num_entries_in_row / batch_size + (num_entries_in_row % batch_size != 0);
619 batches += batches_per_lid(i);
620 },
621 num_batches);
622 Kokkos::resize(batch_info, num_batches);
623
624 Kokkos::HostSpace host_space;
625 auto batches_per_lid_h = Kokkos::create_mirror_view(host_space, batches_per_lid);
626 // DEEP_COPY REVIEW - DEVICE-TO-HOSTMIRROR
627 Kokkos::deep_copy(XS(), batches_per_lid_h, batches_per_lid);
628
629 auto batch_info_h = Kokkos::create_mirror_view(host_space, batch_info);
630
631 XS().fence();
632 (void)compute_batch_info(batches_per_lid_h, batch_info_h);
633 // DEEP_COPY REVIEW - HOSTMIRROR-TO-DEVICE
634 Kokkos::deep_copy(XS(), batch_info, batch_info_h);
635
636 // FIXME (TJF SEP 2017)
637 // The scalar type is not necessarily default constructible
638 size_t bytes_per_value = PackTraits<ST>::packValueCount(ST());
639
640 // Now do the actual unpack!
641 const bool atomic = XS().concurrency() != 1;
643 functor f(
644 local_matrix,
645 local_map,
646 imports,
647 num_packets_per_lid,
648 import_lids,
649 batch_info,
650 offsets,
651 combine_mode,
652 batch_size,
653 bytes_per_value,
654 atomic);
655
656 using policy = Kokkos::TeamPolicy<XS, Kokkos::IndexType<LO>>;
658 if (!Spaces::is_gpu_exec_space<XS>() || team_size == Teuchos::OrdinalTraits<size_t>::invalid()) {
659 Kokkos::parallel_for(policy(static_cast<LO>(num_batches), Kokkos::AUTO), f);
660 } else {
661 Kokkos::parallel_for(policy(static_cast<LO>(num_batches), static_cast<int>(team_size)), f);
662 }
663
664 auto error_code = f.error();
665 TEUCHOS_TEST_FOR_EXCEPTION(
666 error_code != 0,
667 std::runtime_error,
668 prefix << "UnpackCrsMatrixAndCombineFunctor reported error code " << error_code);
669} // unpackAndCombineIntoCrsMatrix (Kokkos version)
670
671template <class LocalMatrix, class BufferDeviceType>
672size_t
674 const LocalMatrix& local_matrix,
676#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
677 const Kokkos::View<const char*, BufferDeviceType, void, void>& imports,
678 const Kokkos::View<const size_t*, BufferDeviceType, void, void>& num_packets_per_lid,
679#else
680 const Kokkos::View<const char*, BufferDeviceType>& imports,
681 const Kokkos::View<const size_t*, BufferDeviceType>& num_packets_per_lid,
682#endif
683 const size_t num_same_ids) {
684 using Kokkos::parallel_reduce;
685 typedef typename LocalMatrix::ordinal_type LO;
686 typedef typename LocalMatrix::device_type device_type;
687 typedef typename device_type::execution_space XS;
688 typedef typename Kokkos::View<LO*, device_type>::size_type size_type;
689 typedef Kokkos::RangePolicy<XS, Kokkos::IndexType<LO>> range_policy;
690 typedef BufferDeviceType BDT;
691
692 size_t count = 0;
693 LO num_items;
694
695 // Number of matrix entries to unpack (returned by this function).
696 num_items = static_cast<LO>(num_same_ids);
697 if (num_items) {
698 size_t kcnt = 0;
699 parallel_reduce(
700 range_policy(0, num_items),
701 KOKKOS_LAMBDA(const LO lid, size_t& update) {
702 update += static_cast<size_t>(local_matrix.graph.row_map[lid + 1] - local_matrix.graph.row_map[lid]);
703 },
704 kcnt);
705 count += kcnt;
706 }
707
708 // Count entries copied directly from the source matrix with permuting.
709 num_items = static_cast<LO>(permute_from_lids.extent(0));
710 if (num_items) {
711 size_t kcnt = 0;
712 parallel_reduce(
713 range_policy(0, num_items),
714 KOKKOS_LAMBDA(const LO i, size_t& update) {
715 const LO lid = permute_from_lids(i);
716 update += static_cast<size_t>(local_matrix.graph.row_map[lid + 1] - local_matrix.graph.row_map[lid]);
717 },
718 kcnt);
719 count += kcnt;
720 }
721
722 {
723 // Count entries received from other MPI processes.
724 const size_type np = num_packets_per_lid.extent(0);
725 Kokkos::View<size_t*, device_type> offsets("offsets", np + 1);
726 computeOffsetsFromCounts(offsets, num_packets_per_lid);
727 count +=
729 offsets, imports);
730 }
731
732 return count;
733} // unpackAndCombineWithOwningPIDsCount (Kokkos version)
734
736template <class LO, class DT, class BDT>
738 const typename PackTraits<size_t>::output_array_type& tgt_rowptr,
739 const typename PackTraits<LO>::input_array_type& import_lids,
740 const Kokkos::View<const char*, BDT>& imports,
741 const Kokkos::View<const size_t*, BDT>& num_packets_per_lid,
742 const typename PackTraits<size_t>::input_array_type& offsets) {
743 using Kokkos::parallel_reduce;
744 typedef typename DT::execution_space XS;
745 typedef typename PackTraits<size_t>::input_array_type::size_type size_type;
746 typedef Kokkos::RangePolicy<XS, Kokkos::IndexType<size_type>> range_policy;
747
748 const size_t InvalidNum = OrdinalTraits<size_t>::invalid();
749 const size_type N = num_packets_per_lid.extent(0);
750
751 int errors = 0;
752 parallel_reduce(
753 "Setup row pointers for remotes",
754 range_policy(0, N),
755 KOKKOS_LAMBDA(const size_t i, int& k_error) {
756 typedef typename std::remove_reference<decltype(tgt_rowptr(0))>::type atomic_incr_type;
757 const size_t num_bytes = num_packets_per_lid(i);
758 const size_t offset = offsets(i);
759 const size_t num_ent = unpackRowCount<LO>(imports.data(), offset, num_bytes);
760 if (num_ent == InvalidNum) {
761 k_error += 1;
762 }
763 Kokkos::atomic_fetch_add(&tgt_rowptr(import_lids(i)), atomic_incr_type(num_ent));
764 },
765 errors);
766 return errors;
767}
768
769// Convert array of row lengths to a CRS pointer array
770template <class DT>
771void makeCrsRowPtrFromLengths(
772 const typename PackTraits<size_t>::output_array_type& tgt_rowptr,
773 const Kokkos::View<size_t*, DT>& new_start_row) {
774 using Kokkos::parallel_scan;
775 typedef typename DT::execution_space XS;
776 typedef typename Kokkos::View<size_t*, DT>::size_type size_type;
777 typedef Kokkos::RangePolicy<XS, Kokkos::IndexType<size_type>> range_policy;
778 const size_type N = new_start_row.extent(0);
779 parallel_scan(
780 range_policy(0, N),
781 KOKKOS_LAMBDA(const size_t& i, size_t& update, const bool& final) {
782 auto cur_val = tgt_rowptr(i);
783 if (final) {
784 tgt_rowptr(i) = update;
785 new_start_row(i) = tgt_rowptr(i);
786 }
787 update += cur_val;
788 });
789}
790
791template <class LocalMatrix, class LocalMap>
792void copyDataFromSameIDs(
794 const typename PackTraits<int>::output_array_type& tgt_pids,
796 const Kokkos::View<size_t*, typename LocalMap::device_type>& new_start_row,
797 const typename PackTraits<size_t>::output_array_type& tgt_rowptr,
798 const typename PackTraits<int>::input_array_type& src_pids,
799 const LocalMatrix& local_matrix,
800 const LocalMap& local_col_map,
801 const size_t num_same_ids,
802 const int my_pid) {
803 using Kokkos::parallel_for;
804 typedef typename LocalMap::device_type DT;
805 typedef typename LocalMap::local_ordinal_type LO;
806 typedef typename DT::execution_space XS;
807 typedef Kokkos::RangePolicy<XS, Kokkos::IndexType<size_t>> range_policy;
808
809 parallel_for(
810 range_policy(0, num_same_ids),
811 KOKKOS_LAMBDA(const size_t i) {
812 typedef typename std::remove_reference<decltype(new_start_row(0))>::type atomic_incr_type;
813
814 const LO src_lid = static_cast<LO>(i);
815 size_t src_row = local_matrix.graph.row_map(src_lid);
816
817 const LO tgt_lid = static_cast<LO>(i);
818 const size_t tgt_row = tgt_rowptr(tgt_lid);
819
820 const size_t nsr = local_matrix.graph.row_map(src_lid + 1) - local_matrix.graph.row_map(src_lid);
821 Kokkos::atomic_fetch_add(&new_start_row(tgt_lid), atomic_incr_type(nsr));
822
823 for (size_t j = local_matrix.graph.row_map(src_lid);
824 j < local_matrix.graph.row_map(src_lid + 1); ++j) {
825 LO src_col = local_matrix.graph.entries(j);
826 tgt_vals(tgt_row + j - src_row) = local_matrix.values(j);
827 tgt_colind(tgt_row + j - src_row) = local_col_map.getGlobalElement(src_col);
828 tgt_pids(tgt_row + j - src_row) = (src_pids(src_col) != my_pid) ? src_pids(src_col) : -1;
829 }
830 });
831}
832
833template <class LocalMatrix, class LocalMap>
834void copyDataFromPermuteIDs(
836 const typename PackTraits<int>::output_array_type& tgt_pids,
838 const Kokkos::View<size_t*, typename LocalMap::device_type>& new_start_row,
839 const typename PackTraits<size_t>::output_array_type& tgt_rowptr,
840 const typename PackTraits<int>::input_array_type& src_pids,
843 const LocalMatrix& local_matrix,
844 const LocalMap& local_col_map,
845 const int my_pid) {
846 using Kokkos::parallel_for;
847 typedef typename LocalMap::device_type DT;
848 typedef typename LocalMap::local_ordinal_type LO;
849 typedef typename DT::execution_space XS;
850 typedef typename PackTraits<LO>::input_array_type::size_type size_type;
851 typedef Kokkos::RangePolicy<XS, Kokkos::IndexType<size_type>> range_policy;
852
853 const size_type num_permute_to_lids = permute_to_lids.extent(0);
854
855 parallel_for(
856 range_policy(0, num_permute_to_lids),
857 KOKKOS_LAMBDA(const size_t i) {
858 typedef typename std::remove_reference<decltype(new_start_row(0))>::type atomic_incr_type;
859
860 const LO src_lid = permute_from_lids(i);
861 const size_t src_row = local_matrix.graph.row_map(src_lid);
862
863 const LO tgt_lid = permute_to_lids(i);
864 const size_t tgt_row = tgt_rowptr(tgt_lid);
865
866 size_t nsr = local_matrix.graph.row_map(src_lid + 1) - local_matrix.graph.row_map(src_lid);
867 Kokkos::atomic_fetch_add(&new_start_row(tgt_lid), atomic_incr_type(nsr));
868
869 for (size_t j = local_matrix.graph.row_map(src_lid);
870 j < local_matrix.graph.row_map(src_lid + 1); ++j) {
871 LO src_col = local_matrix.graph.entries(j);
872 tgt_vals(tgt_row + j - src_row) = local_matrix.values(j);
873 tgt_colind(tgt_row + j - src_row) = local_col_map.getGlobalElement(src_col);
874 tgt_pids(tgt_row + j - src_row) = (src_pids(src_col) != my_pid) ? src_pids(src_col) : -1;
875 }
876 });
877}
878
879template <typename LocalMatrix, typename LocalMap, typename BufferDeviceType>
880int unpackAndCombineIntoCrsArrays2(
882 const typename PackTraits<int>::output_array_type& tgt_pids,
884 const Kokkos::View<size_t*, typename LocalMap::device_type>& new_start_row,
885 const typename PackTraits<size_t>::input_array_type& offsets,
887#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
888 const Kokkos::View<const char*, BufferDeviceType, void, void>& imports,
889 const Kokkos::View<const size_t*, BufferDeviceType, void, void>& num_packets_per_lid,
890#else
891 const Kokkos::View<const char*, BufferDeviceType>& imports,
892 const Kokkos::View<const size_t*, BufferDeviceType>& num_packets_per_lid,
893#endif
894 const LocalMatrix& /* local_matrix */,
895 const LocalMap /*& local_col_map*/,
896 const int my_pid,
897 const size_t bytes_per_value) {
898 using Kokkos::atomic_fetch_add;
899 using Kokkos::MemoryUnmanaged;
900 using Kokkos::parallel_reduce;
901 using Kokkos::subview;
902 using Kokkos::View;
903 using Tpetra::Details::PackTraits;
904 typedef typename LocalMap::device_type DT;
905 typedef typename LocalMap::local_ordinal_type LO;
906 typedef typename LocalMap::global_ordinal_type GO;
907 typedef typename LocalMatrix::value_type ST;
908 typedef typename DT::execution_space XS;
909 typedef typename Kokkos::View<LO*, DT>::size_type size_type;
910 typedef typename Kokkos::pair<size_type, size_type> slice;
911 typedef Kokkos::RangePolicy<XS, Kokkos::IndexType<size_type>> range_policy;
912
913 typedef View<int*, DT, MemoryUnmanaged> pids_out_type;
914 typedef View<GO*, DT, MemoryUnmanaged> gids_out_type;
915 typedef View<ST*, DT, MemoryUnmanaged> vals_out_type;
916
917 const size_t InvalidNum = OrdinalTraits<size_t>::invalid();
918
919 int errors = 0;
920 const size_type num_import_lids = import_lids.size();
921
922 // RemoteIDs: Loop structure following UnpackAndCombine
923 parallel_reduce(
924 "Unpack and combine into CRS",
925 range_policy(0, num_import_lids),
926 KOKKOS_LAMBDA(const size_t i, int& k_error) {
927 typedef typename std::remove_reference<decltype(new_start_row(0))>::type atomic_incr_type;
928 const size_t num_bytes = num_packets_per_lid(i);
929 const size_t offset = offsets(i);
930 if (num_bytes == 0) {
931 // Empty buffer means that the row is empty.
932 return;
933 }
934 size_t num_ent = unpackRowCount<LO>(imports.data(), offset, num_bytes);
935 if (num_ent == InvalidNum) {
936 k_error += 1;
937 return;
938 }
939 const LO lcl_row = import_lids(i);
940 const size_t start_row = atomic_fetch_add(&new_start_row(lcl_row), atomic_incr_type(num_ent));
941 const size_t end_row = start_row + num_ent;
942
943 gids_out_type gids_out = subview(tgt_colind, slice(start_row, end_row));
944 vals_out_type vals_out = subview(tgt_vals, slice(start_row, end_row));
945 pids_out_type pids_out = subview(tgt_pids, slice(start_row, end_row));
946
947 k_error += unpackRow<ST, LO, GO>(gids_out, pids_out, vals_out,
948 imports.data(), offset, num_bytes,
949 num_ent, bytes_per_value);
950
951 // Correct target PIDs.
952 for (size_t j = 0; j < static_cast<size_t>(num_ent); ++j) {
953 const int pid = pids_out(j);
954 pids_out(j) = (pid != my_pid) ? pid : -1;
955 }
956 },
957 errors);
958
959 return errors;
960}
961
962template <typename LocalMatrix, typename LocalMap, typename BufferDeviceType>
963void unpackAndCombineIntoCrsArrays(
964 const LocalMatrix& local_matrix,
965 const LocalMap& local_col_map,
967#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
968 const Kokkos::View<const char*, BufferDeviceType, void, void>& imports,
969 const Kokkos::View<const size_t*, BufferDeviceType, void, void>& num_packets_per_lid,
970#else
971 const Kokkos::View<const char*, BufferDeviceType>& imports,
972 const Kokkos::View<const size_t*, BufferDeviceType>& num_packets_per_lid,
973#endif
976 const typename PackTraits<size_t>::output_array_type& tgt_rowptr,
979 const typename PackTraits<int>::input_array_type& src_pids,
980 const typename PackTraits<int>::output_array_type& tgt_pids,
981 const size_t num_same_ids,
982 const size_t tgt_num_rows,
983 const size_t tgt_num_nonzeros,
984 const int my_tgt_pid,
985 const size_t bytes_per_value) {
986 using Kokkos::MemoryUnmanaged;
987 using Kokkos::parallel_for;
988 using Kokkos::subview;
989 using Kokkos::View;
990 using Tpetra::Details::PackTraits;
991 typedef typename LocalMap::device_type DT;
992 typedef typename LocalMap::local_ordinal_type LO;
993 typedef typename DT::execution_space XS;
994 typedef typename Kokkos::View<LO*, DT>::size_type size_type;
995 typedef Kokkos::RangePolicy<XS, Kokkos::IndexType<size_t>> range_policy;
996 typedef BufferDeviceType BDT;
997
998 const char prefix[] = "unpackAndCombineIntoCrsArrays: ";
999
1000 const size_t N = tgt_num_rows;
1001
1002 // In the case of reduced communicators, the sourceMatrix won't have
1003 // the right "my_pid", so thus we have to supply it.
1004 const int my_pid = my_tgt_pid;
1005
1006 // Zero the rowptr
1007 parallel_for(
1008 range_policy(0, N + 1),
1009 KOKKOS_LAMBDA(const size_t i) {
1010 tgt_rowptr(i) = 0;
1011 });
1012
1013 // same IDs: Always first, always in the same place
1014 parallel_for(
1015 range_policy(0, num_same_ids),
1016 KOKKOS_LAMBDA(const size_t i) {
1017 const LO tgt_lid = static_cast<LO>(i);
1018 const LO src_lid = static_cast<LO>(i);
1019 tgt_rowptr(tgt_lid) = local_matrix.graph.row_map(src_lid + 1) - local_matrix.graph.row_map(src_lid);
1020 });
1021
1022 // Permute IDs: Still local, but reordered
1023 const size_type num_permute_to_lids = permute_to_lids.extent(0);
1024 parallel_for(
1025 range_policy(0, num_permute_to_lids),
1026 KOKKOS_LAMBDA(const size_t i) {
1027 const LO tgt_lid = permute_to_lids(i);
1028 const LO src_lid = permute_from_lids(i);
1029 tgt_rowptr(tgt_lid) = local_matrix.graph.row_map(src_lid + 1) - local_matrix.graph.row_map(src_lid);
1030 });
1031
1032 // Get the offsets from the number of packets per LID
1033 const size_type num_import_lids = import_lids.extent(0);
1034 View<size_t*, DT> offsets("offsets", num_import_lids + 1);
1035 computeOffsetsFromCounts(offsets, num_packets_per_lid);
1036
1037#ifdef HAVE_TPETRA_DEBUG
1038 {
1039 auto nth_offset_h = getEntryOnHost(offsets, num_import_lids);
1040 const bool condition =
1041 nth_offset_h != static_cast<size_t>(imports.extent(0));
1042 TEUCHOS_TEST_FOR_EXCEPTION(condition, std::logic_error, prefix << "The final offset in bytes " << nth_offset_h << " != imports.size() = " << imports.extent(0) << ". Please report this bug to the Tpetra developers.");
1043 }
1044#endif // HAVE_TPETRA_DEBUG
1045
1046 // Setup row pointers for remotes
1047 int k_error =
1049 import_lids, imports, num_packets_per_lid, offsets);
1050 TEUCHOS_TEST_FOR_EXCEPTION(k_error != 0, std::logic_error, prefix << " Error transferring data to target row pointers. "
1051 "Please report this bug to the Tpetra developers.");
1052
1053 // If multiple processes contribute to the same row, we may need to
1054 // update row offsets. This tracks that.
1055 View<size_t*, DT> new_start_row("new_start_row", N + 1);
1056
1057 // Turn row length into a real CRS row pointer
1058 makeCrsRowPtrFromLengths(tgt_rowptr, new_start_row);
1059
1060 // SameIDs: Copy the data over
1061 copyDataFromSameIDs(tgt_colind, tgt_pids, tgt_vals, new_start_row,
1062 tgt_rowptr, src_pids, local_matrix, local_col_map, num_same_ids, my_pid);
1063
1064 copyDataFromPermuteIDs(tgt_colind, tgt_pids, tgt_vals, new_start_row,
1065 tgt_rowptr, src_pids, permute_to_lids, permute_from_lids,
1066 local_matrix, local_col_map, my_pid);
1067
1068 if (imports.extent(0) <= 0) {
1069 return;
1070 }
1071
1072 int unpack_err = unpackAndCombineIntoCrsArrays2(tgt_colind, tgt_pids,
1073 tgt_vals, new_start_row, offsets, import_lids, imports, num_packets_per_lid,
1074 local_matrix, local_col_map, my_pid, bytes_per_value);
1075 TEUCHOS_TEST_FOR_EXCEPTION(
1076 unpack_err != 0, std::logic_error, prefix << "unpack loop failed. This "
1077 "should never happen. Please report this bug to the Tpetra developers.");
1078
1079 return;
1080}
1081
1082} // namespace UnpackAndCombineCrsMatrixImpl
1083
1118template <typename ST, typename LO, typename GO, typename Node>
1120 const CrsMatrix<ST, LO, GO, Node>& sourceMatrix,
1121 const Teuchos::ArrayView<const char>& imports,
1122 const Teuchos::ArrayView<const size_t>& numPacketsPerLID,
1123 const Teuchos::ArrayView<const LO>& importLIDs,
1124 size_t /* constantNumPackets */,
1125 CombineMode combineMode) {
1126 using Kokkos::View;
1127 typedef typename Node::device_type device_type;
1129 static_assert(std::is_same<device_type, typename local_matrix_device_type::device_type>::value,
1130 "Node::device_type and LocalMatrix::device_type must be the same.");
1131
1132 // Convert all Teuchos::Array to Kokkos::View.
1133 device_type outputDevice;
1134
1135 // numPacketsPerLID, importLIDs, and imports are input, so we have to copy
1136 // them to device. Since unpacking is done directly in to the local matrix
1137 // (lclMatrix), no copying needs to be performed after unpacking.
1138 auto num_packets_per_lid_d =
1139 create_mirror_view_from_raw_host_array(outputDevice, numPacketsPerLID.getRawPtr(),
1140 numPacketsPerLID.size(), true, "num_packets_per_lid");
1141
1142 auto import_lids_d =
1143 create_mirror_view_from_raw_host_array(outputDevice, importLIDs.getRawPtr(),
1144 importLIDs.size(), true, "import_lids");
1145
1146 auto imports_d =
1147 create_mirror_view_from_raw_host_array(outputDevice, imports.getRawPtr(),
1148 imports.size(), true, "imports");
1149
1150 auto local_matrix = sourceMatrix.getLocalMatrixDevice();
1151 auto local_col_map = sourceMatrix.getColMap()->getLocalMap();
1152
1153 // KDDKDD This loop doesn't appear to do anything; what is it?
1154 // KDDKDD for (int i=0; i<importLIDs.size(); i++)
1155 // KDDKDD {
1156 // KDDKDD auto lclRow = importLIDs[i];
1157 // KDDKDD Teuchos::ArrayView<const LO> A_indices;
1158 // KDDKDD Teuchos::ArrayView<const ST> A_values;
1159 // KDDKDD sourceMatrix.getLocalRowView(lclRow, A_indices, A_values);
1160 // KDDKDD }
1161 // Now do the actual unpack!
1163 local_matrix, local_col_map, imports_d, num_packets_per_lid_d,
1164 import_lids_d, combineMode);
1165}
1166
1167template <typename ST, typename LO, typename GO, typename NT>
1168void unpackCrsMatrixAndCombineNew(
1169 const CrsMatrix<ST, LO, GO, NT>& sourceMatrix,
1170 Kokkos::DualView<char*,
1172 imports,
1173 Kokkos::DualView<size_t*,
1175 numPacketsPerLID,
1176 const Kokkos::DualView<const LO*,
1178 const size_t /* constantNumPackets */,
1179 const CombineMode combineMode) {
1180 using Kokkos::View;
1181 using crs_matrix_type = CrsMatrix<ST, LO, GO, NT>;
1182 using dist_object_type = DistObject<char, LO, GO, NT>;
1183 using device_type = typename crs_matrix_type::device_type;
1184 using local_matrix_device_type = typename crs_matrix_type::local_matrix_device_type;
1185 using buffer_device_type = typename dist_object_type::buffer_device_type;
1186
1187 static_assert(std::is_same<device_type, typename local_matrix_device_type::device_type>::value,
1188 "crs_matrix_type::device_type and local_matrix_device_type::device_type "
1189 "must be the same.");
1190
1191 if (numPacketsPerLID.need_sync_device()) {
1192 numPacketsPerLID.sync_device();
1193 }
1194 auto num_packets_per_lid_d = numPacketsPerLID.view_device();
1195
1196 TEUCHOS_ASSERT(!importLIDs.need_sync_device());
1197 auto import_lids_d = importLIDs.view_device();
1198
1199 if (imports.need_sync_device()) {
1200 imports.sync_device();
1201 }
1202 auto imports_d = imports.view_device();
1203
1204 auto local_matrix = sourceMatrix.getLocalMatrixDevice();
1205 auto local_col_map = sourceMatrix.getColMap()->getLocalMap();
1206 typedef decltype(local_col_map) local_map_type;
1207
1209 local_matrix_device_type,
1210 local_map_type,
1211 buffer_device_type>(local_matrix, local_col_map, imports_d, num_packets_per_lid_d,
1212 import_lids_d, combineMode);
1213}
1214
1261//
1270template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, typename Node>
1271size_t
1274 const Teuchos::ArrayView<const LocalOrdinal>& importLIDs,
1275 const Teuchos::ArrayView<const char>& imports,
1276 const Teuchos::ArrayView<const size_t>& numPacketsPerLID,
1277 size_t /* constantNumPackets */,
1278 CombineMode /* combineMode */,
1279 size_t numSameIDs,
1280 const Teuchos::ArrayView<const LocalOrdinal>& permuteToLIDs,
1281 const Teuchos::ArrayView<const LocalOrdinal>& permuteFromLIDs) {
1282 using Kokkos::MemoryUnmanaged;
1283 using Kokkos::View;
1284 typedef typename Node::device_type DT;
1285 const char prefix[] = "unpackAndCombineWithOwningPIDsCount: ";
1286
1287 TEUCHOS_TEST_FOR_EXCEPTION(permuteToLIDs.size() != permuteFromLIDs.size(), std::invalid_argument,
1288 prefix << "permuteToLIDs.size() = " << permuteToLIDs.size() << " != "
1289 "permuteFromLIDs.size() = "
1290 << permuteFromLIDs.size() << ".");
1291 // FIXME (mfh 26 Jan 2015) If there are no entries on the calling
1292 // process, then the matrix is neither locally nor globally indexed.
1293 const bool locallyIndexed = sourceMatrix.isLocallyIndexed();
1294 TEUCHOS_TEST_FOR_EXCEPTION(!locallyIndexed, std::invalid_argument, prefix << "The input "
1295 "CrsMatrix 'sourceMatrix' must be locally indexed.");
1296 TEUCHOS_TEST_FOR_EXCEPTION(importLIDs.size() != numPacketsPerLID.size(), std::invalid_argument,
1297 prefix << "importLIDs.size() = " << importLIDs.size() << " != "
1298 "numPacketsPerLID.size() = "
1299 << numPacketsPerLID.size() << ".");
1300
1301 auto local_matrix = sourceMatrix.getLocalMatrixDevice();
1302
1303 using kokkos_device_type = Kokkos::Device<typename Node::device_type::execution_space,
1304 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>;
1305
1306#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1307 Kokkos::View<LocalOrdinal const*, kokkos_device_type, void, void> permute_from_lids_d =
1308#else
1309 Kokkos::View<LocalOrdinal const*, kokkos_device_type> permute_from_lids_d =
1310#endif
1312 permuteFromLIDs.getRawPtr(),
1313 permuteFromLIDs.size(), true,
1314 "permute_from_lids");
1315
1316#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1317 Kokkos::View<const char*, kokkos_device_type, void, void> imports_d =
1318#else
1319 Kokkos::View<const char*, kokkos_device_type> imports_d =
1320#endif
1322 imports.getRawPtr(),
1323 imports.size(), true,
1324 "imports");
1325
1326#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1327 Kokkos::View<const size_t*, kokkos_device_type, void, void> num_packets_per_lid_d =
1328#else
1329 Kokkos::View<const size_t*, kokkos_device_type> num_packets_per_lid_d =
1330#endif
1332 numPacketsPerLID.getRawPtr(),
1333 numPacketsPerLID.size(), true,
1334 "num_packets_per_lid");
1335
1336 return UnpackAndCombineCrsMatrixImpl::unpackAndCombineWithOwningPIDsCount(
1337 local_matrix, permute_from_lids_d, imports_d,
1338 num_packets_per_lid_d, numSameIDs);
1339} // unpackAndCombineWithOwningPIDsCount (Teuchos::Array version)
1340
1355
1356template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, typename Node>
1359 const Kokkos::View<LocalOrdinal const*,
1360 Kokkos::Device<typename Node::device_type::execution_space,
1361 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>
1362#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1363 ,
1364 void, void
1365#endif
1366 >
1367 import_lids_d,
1368 const Kokkos::View<const char*,
1369 Kokkos::Device<typename Node::device_type::execution_space,
1370 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>
1371#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1372 ,
1373 void, void
1374#endif
1375 >
1376 imports_d,
1377 const Kokkos::View<const size_t*,
1378 Kokkos::Device<typename Node::device_type::execution_space,
1379 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>
1380#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1381 ,
1382 void, void
1383#endif
1384 >
1385 num_packets_per_lid_d,
1386 const size_t numSameIDs,
1387 const Kokkos::View<LocalOrdinal const*,
1388 Kokkos::Device<typename Node::device_type::execution_space,
1389 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>
1390#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1391 ,
1392 void, void
1393#endif
1394 >
1395 permute_to_lids_d,
1396 const Kokkos::View<LocalOrdinal const*,
1397 Kokkos::Device<typename Node::device_type::execution_space,
1398 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>
1399#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1400 ,
1401 void, void
1402#endif
1403 >
1404 permute_from_lids_d,
1405 size_t TargetNumRows,
1406 const int MyTargetPID,
1407 Kokkos::View<size_t*, typename Node::device_type>& crs_rowptr_d,
1408 Kokkos::View<GlobalOrdinal*, typename Node::device_type>& crs_colind_d,
1409 Kokkos::View<typename CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::impl_scalar_type*, typename Node::device_type>& crs_vals_d,
1410 const Teuchos::ArrayView<const int>& SourcePids,
1411 Kokkos::View<int*, typename Node::device_type>& TargetPids) {
1412 using execution_space = typename Node::execution_space;
1414
1415 using Kokkos::deep_copy;
1416 using Kokkos::View;
1417
1418 using Teuchos::ArrayView;
1419 using Teuchos::outArg;
1420 using Teuchos::REDUCE_MAX;
1421 using Teuchos::reduceAll;
1422
1423 typedef typename Node::device_type DT;
1424
1426 typedef typename matrix_type::impl_scalar_type ST;
1427
1428 const char prefix[] = "Tpetra::Details::unpackAndCombineIntoCrsArrays_new: ";
1429 Teuchos::RCP<Tpetra::Details::ProfilingRegion> tm;
1430
1431 using Kokkos::MemoryUnmanaged;
1432
1433 TEUCHOS_TEST_FOR_EXCEPTION(permute_to_lids_d.size() != permute_from_lids_d.size(), std::invalid_argument,
1434 prefix << "permute_to_lids_d.size() = " << permute_to_lids_d.size() << " != "
1435 "permute_from_lids_d.size() = "
1436 << permute_from_lids_d.size() << ".");
1437 // FIXME (mfh 26 Jan 2015) If there are no entries on the calling
1438 // process, then the matrix is neither locally nor globally indexed.
1439 const bool locallyIndexed = sourceMatrix.isLocallyIndexed();
1440 TEUCHOS_TEST_FOR_EXCEPTION(!locallyIndexed, std::invalid_argument, prefix << "The input "
1441 "CrsMatrix 'sourceMatrix' must be locally indexed.");
1442 TEUCHOS_TEST_FOR_EXCEPTION(((size_t)import_lids_d.size()) != num_packets_per_lid_d.size(), std::invalid_argument,
1443 prefix << "import_lids_d.size() = " << import_lids_d.size() << " != "
1444 "num_packets_per_lid_d.size() = "
1445 << num_packets_per_lid_d.size() << ".");
1446
1447 auto local_matrix = sourceMatrix.getLocalMatrixDevice();
1448
1449 // TargetNumNonzeros is number of nonzeros in local matrix.
1450 tm = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Details::unpackAndCombineIntoCrsArrays_new: unpackAndCombineWithOwningPIDsCount"));
1451 size_t TargetNumNonzeros =
1452 UnpackAndCombineCrsMatrixImpl::unpackAndCombineWithOwningPIDsCount(
1453 local_matrix, permute_from_lids_d, imports_d,
1454 num_packets_per_lid_d, numSameIDs);
1455 tm = Teuchos::null;
1456
1457 tm = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Details::unpackAndCombineIntoCrsArrays_new: resize CRS pointers"));
1458 Kokkos::resize(crs_rowptr_d, TargetNumRows + 1);
1459 Kokkos::resize(crs_colind_d, TargetNumNonzeros);
1460 Kokkos::resize(crs_vals_d, TargetNumNonzeros);
1461 tm = Teuchos::null;
1462
1463 TEUCHOS_TEST_FOR_EXCEPTION(
1464 permute_to_lids_d.size() != permute_from_lids_d.size(), std::invalid_argument,
1465 prefix << "permuteToLIDs.size() = " << permute_to_lids_d.size()
1466 << "!= permute_from_lids_d.size() = " << permute_from_lids_d.size() << ".");
1467
1468 if (static_cast<size_t>(TargetPids.size()) != TargetNumNonzeros) {
1469 Kokkos::resize(TargetPids, TargetNumNonzeros);
1470 }
1471 Kokkos::deep_copy(execution_space(), TargetPids, -1);
1472
1473 // Grab pointers for sourceMatrix
1474 auto local_col_map = sourceMatrix.getColMap()->getLocalMap();
1475
1476 tm = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Details::unpackAndCombineIntoCrsArrays_new: create mirror views from inputs"));
1477 // Convert input arrays to Kokkos::Views
1478 DT outputDevice;
1479
1480 auto src_pids_d =
1481 create_mirror_view_from_raw_host_array(outputDevice, SourcePids.getRawPtr(),
1482 SourcePids.size(), true, "src_pids");
1483
1484 tm = Teuchos::null;
1485
1486 size_t bytes_per_value = 0;
1488 // assume that ST is default constructible
1489 bytes_per_value = PackTraits<ST>::packValueCount(ST());
1490 } else {
1491 // Since the packed data come from the source matrix, we can use the source
1492 // matrix to get the number of bytes per Scalar value stored in the matrix.
1493 // This assumes that all Scalar values in the source matrix require the same
1494 // number of bytes. If the source matrix has no entries on the calling
1495 // process, then we hope that some process does have some idea how big
1496 // a Scalar value is. Of course, if no processes have any entries, then no
1497 // values should be packed (though this does assume that in our packing
1498 // scheme, rows with zero entries take zero bytes).
1499 size_t bytes_per_value_l = 0;
1500 if (local_matrix.values.extent(0) > 0) {
1501 const ST& val = local_matrix.values(0);
1502 bytes_per_value_l = PackTraits<ST>::packValueCount(val);
1503 } else {
1504 const ST& val = crs_vals_d(0);
1505 bytes_per_value_l = PackTraits<ST>::packValueCount(val);
1506 }
1507 Teuchos::reduceAll<int, size_t>(*(sourceMatrix.getComm()),
1508 Teuchos::REDUCE_MAX,
1509 bytes_per_value_l,
1510 outArg(bytes_per_value));
1511 }
1512
1513 tm = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Details::unpackAndCombineIntoCrsArrays_new: unpackAndCombineIntoCrsArrays"));
1514 UnpackAndCombineCrsMatrixImpl::unpackAndCombineIntoCrsArrays(
1515 local_matrix, local_col_map, import_lids_d, imports_d,
1516 num_packets_per_lid_d, permute_to_lids_d, permute_from_lids_d,
1517 crs_rowptr_d, crs_colind_d, crs_vals_d, src_pids_d, TargetPids,
1518 numSameIDs, TargetNumRows, TargetNumNonzeros, MyTargetPID,
1519 bytes_per_value);
1520 tm = Teuchos::null;
1521
1522 // Copy outputs back to host
1523 tm = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Details::unpackAndCombineIntoCrsArrays_new: copy back to host"));
1524
1525 Kokkos::parallel_for(
1526 "setLocalEntriesToPID", Kokkos::RangePolicy<typename DT::execution_space>(0, TargetPids.size()), KOKKOS_LAMBDA(const size_t i) {
1527 if (TargetPids(i) == -1) TargetPids(i) = MyTargetPID;
1528 });
1529
1530} // unpackAndCombineIntoCrsArrays
1531
1532template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, typename Node>
1535 const Kokkos::View<LocalOrdinal const*,
1536 Kokkos::Device<typename Node::device_type::execution_space,
1537 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>
1538#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1539 ,
1540 void, void
1541#endif
1542 >
1543 import_lids_d,
1544 const Kokkos::View<const char*,
1545 Kokkos::Device<typename Node::device_type::execution_space,
1546 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>
1547#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1548 ,
1549 void, void
1550#endif
1551 >
1552 imports_d,
1553 const Kokkos::View<const size_t*,
1554 Kokkos::Device<typename Node::device_type::execution_space,
1555 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>
1556#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1557 ,
1558 void, void
1559#endif
1560 >
1561 num_packets_per_lid_d,
1562 const size_t numSameIDs,
1563 const Kokkos::View<LocalOrdinal const*,
1564 Kokkos::Device<typename Node::device_type::execution_space,
1565 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>
1566#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1567 ,
1568 void, void
1569#endif
1570 >
1571 permute_to_lids_d,
1572 const Kokkos::View<LocalOrdinal const*,
1573 Kokkos::Device<typename Node::device_type::execution_space,
1574 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename Node::device_type>>
1575#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1576 ,
1577 void, void
1578#endif
1579 >
1580 permute_from_lids_d,
1581 size_t TargetNumRows,
1582 const int MyTargetPID,
1583 Teuchos::ArrayRCP<size_t>& CRS_rowptr,
1584 Teuchos::ArrayRCP<GlobalOrdinal>& CRS_colind,
1585 Teuchos::ArrayRCP<Scalar>& CRS_vals,
1586 const Teuchos::ArrayView<const int>& SourcePids,
1587 Teuchos::Array<int>& TargetPids) {
1588 using execution_space = typename Node::execution_space;
1590
1591 using Kokkos::deep_copy;
1592 using Kokkos::View;
1593
1594 using Teuchos::ArrayView;
1595 using Teuchos::outArg;
1596 using Teuchos::REDUCE_MAX;
1597 using Teuchos::reduceAll;
1598
1599 typedef typename Node::device_type DT;
1600
1602 typedef typename matrix_type::impl_scalar_type ST;
1603
1604 const char prefix[] = "Tpetra::Details::unpackAndCombineIntoCrsArrays_new: ";
1605 Teuchos::RCP<Tpetra::Details::ProfilingRegion> tm;
1606
1607 using Kokkos::MemoryUnmanaged;
1608
1609 TEUCHOS_TEST_FOR_EXCEPTION(permute_to_lids_d.size() != permute_from_lids_d.size(), std::invalid_argument,
1610 prefix << "permute_to_lids_d.size() = " << permute_to_lids_d.size() << " != "
1611 "permute_from_lids_d.size() = "
1612 << permute_from_lids_d.size() << ".");
1613 // FIXME (mfh 26 Jan 2015) If there are no entries on the calling
1614 // process, then the matrix is neither locally nor globally indexed.
1615 const bool locallyIndexed = sourceMatrix.isLocallyIndexed();
1616 TEUCHOS_TEST_FOR_EXCEPTION(!locallyIndexed, std::invalid_argument, prefix << "The input "
1617 "CrsMatrix 'sourceMatrix' must be locally indexed.");
1618 TEUCHOS_TEST_FOR_EXCEPTION(((size_t)import_lids_d.size()) != num_packets_per_lid_d.size(), std::invalid_argument,
1619 prefix << "import_lids_d.size() = " << import_lids_d.size() << " != "
1620 "num_packets_per_lid_d.size() = "
1621 << num_packets_per_lid_d.size() << ".");
1622
1623 auto local_matrix = sourceMatrix.getLocalMatrixDevice();
1624
1625 // TargetNumNonzeros is number of nonzeros in local matrix.
1626 tm = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Details::unpackAndCombineIntoCrsArrays_new: unpackAndCombineWithOwningPIDsCount"));
1627 size_t TargetNumNonzeros =
1628 UnpackAndCombineCrsMatrixImpl::unpackAndCombineWithOwningPIDsCount(
1629 local_matrix, permute_from_lids_d, imports_d,
1630 num_packets_per_lid_d, numSameIDs);
1631 tm = Teuchos::null;
1632
1633 tm = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Details::unpackAndCombineIntoCrsArrays_new: resize CRS pointers"));
1634 CRS_rowptr.resize(TargetNumRows + 1);
1635 CRS_colind.resize(TargetNumNonzeros);
1636 CRS_vals.resize(TargetNumNonzeros);
1637 Teuchos::ArrayRCP<ST> const& CRS_vals_impl_scalar_type = Teuchos::arcp_reinterpret_cast<ST>(CRS_vals);
1638 tm = Teuchos::null;
1639
1640 TEUCHOS_TEST_FOR_EXCEPTION(
1641 permute_to_lids_d.size() != permute_from_lids_d.size(), std::invalid_argument,
1642 prefix << "permuteToLIDs.size() = " << permute_to_lids_d.size()
1643 << "!= permute_from_lids_d.size() = " << permute_from_lids_d.size() << ".");
1644
1645 // Preseed TargetPids with -1 for local
1646 if (static_cast<size_t>(TargetPids.size()) != TargetNumNonzeros) {
1647 TargetPids.resize(TargetNumNonzeros);
1648 }
1649 TargetPids.assign(TargetNumNonzeros, -1);
1650
1651 // Grab pointers for sourceMatrix
1652 auto local_col_map = sourceMatrix.getColMap()->getLocalMap();
1653
1654 tm = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Details::unpackAndCombineIntoCrsArrays_new: create mirror views from inputs"));
1655 // Convert input arrays to Kokkos::Views
1656 DT outputDevice;
1657
1658 auto crs_rowptr_d =
1659 create_mirror_view_from_raw_host_array(outputDevice, CRS_rowptr.getRawPtr(),
1660 CRS_rowptr.size(), true, "crs_rowptr");
1661
1662 auto crs_colind_d =
1663 create_mirror_view_from_raw_host_array(outputDevice, CRS_colind.getRawPtr(),
1664 CRS_colind.size(), true, "crs_colidx");
1665#ifdef HAVE_TPETRA_INST_COMPLEX_DOUBLE
1666 static_assert(!std::is_same<
1667 typename std::remove_const<
1668 typename std::decay<
1669 decltype(CRS_vals_impl_scalar_type)>::type::value_type>::type,
1670 std::complex<double>>::value,
1671 "CRS_vals::value_type is std::complex<double>; this should never happen"
1672 ", since std::complex does not work in Kokkos::View objects.");
1673#endif // HAVE_TPETRA_INST_COMPLEX_DOUBLE
1674
1675 auto crs_vals_d =
1676 create_mirror_view_from_raw_host_array(outputDevice, CRS_vals_impl_scalar_type.getRawPtr(),
1677 CRS_vals_impl_scalar_type.size(), true, "crs_vals");
1678
1679#ifdef HAVE_TPETRA_INST_COMPLEX_DOUBLE
1680 static_assert(!std::is_same<
1681 typename decltype(crs_vals_d)::non_const_value_type,
1682 std::complex<double>>::value,
1683 "crs_vals_d::non_const_value_type is std::complex<double>; this should "
1684 "never happen, since std::complex does not work in Kokkos::View objects.");
1685#endif // HAVE_TPETRA_INST_COMPLEX_DOUBLE
1686
1687 auto src_pids_d =
1688 create_mirror_view_from_raw_host_array(outputDevice, SourcePids.getRawPtr(),
1689 SourcePids.size(), true, "src_pids");
1690
1691 auto tgt_pids_d =
1692 create_mirror_view_from_raw_host_array(outputDevice, TargetPids.getRawPtr(),
1693 TargetPids.size(), true, "tgt_pids");
1694
1695 tm = Teuchos::null;
1696
1697 size_t bytes_per_value = 0;
1699 // assume that ST is default constructible
1700 bytes_per_value = PackTraits<ST>::packValueCount(ST());
1701 } else {
1702 // Since the packed data come from the source matrix, we can use the source
1703 // matrix to get the number of bytes per Scalar value stored in the matrix.
1704 // This assumes that all Scalar values in the source matrix require the same
1705 // number of bytes. If the source matrix has no entries on the calling
1706 // process, then we hope that some process does have some idea how big
1707 // a Scalar value is. Of course, if no processes have any entries, then no
1708 // values should be packed (though this does assume that in our packing
1709 // scheme, rows with zero entries take zero bytes).
1710 size_t bytes_per_value_l = 0;
1711 if (local_matrix.values.extent(0) > 0) {
1712 const ST& val = local_matrix.values(0);
1713 bytes_per_value_l = PackTraits<ST>::packValueCount(val);
1714 } else {
1715 const ST& val = crs_vals_d(0);
1716 bytes_per_value_l = PackTraits<ST>::packValueCount(val);
1717 }
1718 Teuchos::reduceAll<int, size_t>(*(sourceMatrix.getComm()),
1719 Teuchos::REDUCE_MAX,
1720 bytes_per_value_l,
1721 outArg(bytes_per_value));
1722 }
1723
1724#ifdef HAVE_TPETRA_INST_COMPLEX_DOUBLE
1725 static_assert(!std::is_same<
1726 typename decltype(crs_vals_d)::non_const_value_type,
1727 std::complex<double>>::value,
1728 "crs_vals_d::non_const_value_type is std::complex<double>; this should "
1729 "never happen, since std::complex does not work in Kokkos::View objects.");
1730#endif // HAVE_TPETRA_INST_COMPLEX_DOUBLE
1731
1732 tm = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Details::unpackAndCombineIntoCrsArrays_new: unpackAndCombineIntoCrsArrays"));
1733 UnpackAndCombineCrsMatrixImpl::unpackAndCombineIntoCrsArrays(
1734 local_matrix, local_col_map, import_lids_d, imports_d,
1735 num_packets_per_lid_d, permute_to_lids_d, permute_from_lids_d,
1736 crs_rowptr_d, crs_colind_d, crs_vals_d, src_pids_d, tgt_pids_d,
1737 numSameIDs, TargetNumRows, TargetNumNonzeros, MyTargetPID,
1738 bytes_per_value);
1739 tm = Teuchos::null;
1740
1741 // Copy outputs back to host
1742 tm = Teuchos::rcp(new Tpetra::Details::ProfilingRegion("Tpetra::Details::unpackAndCombineIntoCrsArrays_new: copy back to host"));
1743 typename decltype(crs_rowptr_d)::host_mirror_type crs_rowptr_h(
1744 CRS_rowptr.getRawPtr(), CRS_rowptr.size());
1745 // DEEP_COPY REVIEW - DEVICE-TO-HOSTMIRROR
1746 deep_copy(execution_space(), crs_rowptr_h, crs_rowptr_d);
1747
1748 typename decltype(crs_colind_d)::host_mirror_type crs_colind_h(
1749 CRS_colind.getRawPtr(), CRS_colind.size());
1750 // DEEP_COPY REVIEW - DEVICE-TO-HOSTMIRROR
1751 deep_copy(execution_space(), crs_colind_h, crs_colind_d);
1752
1753 typename decltype(crs_vals_d)::host_mirror_type crs_vals_h(
1754 CRS_vals_impl_scalar_type.getRawPtr(), CRS_vals_impl_scalar_type.size());
1755 // DEEP_COPY REVIEW - DEVICE-TO-HOSTMIRROR
1756 deep_copy(execution_space(), crs_vals_h, crs_vals_d);
1757
1758 typename decltype(tgt_pids_d)::host_mirror_type tgt_pids_h(
1759 TargetPids.getRawPtr(), TargetPids.size());
1760 // DEEP_COPY REVIEW - DEVICE-TO-HOSTMIRROR
1761 deep_copy(execution_space(), tgt_pids_h, tgt_pids_d);
1762
1763} // unpackAndCombineIntoCrsArrays
1764
1765} // namespace Details
1766} // namespace Tpetra
1767
1768#define TPETRA_DETAILS_UNPACKCRSMATRIXANDCOMBINE_INSTANT_KOKKOS_DEPRECATED_CODE_4_ON(ST, LO, GO, NT) \
1769 template void \
1770 Details::unpackCrsMatrixAndCombine<ST, LO, GO, NT>( \
1771 const CrsMatrix<ST, LO, GO, NT>&, \
1772 const Teuchos::ArrayView<const char>&, \
1773 const Teuchos::ArrayView<const size_t>&, \
1774 const Teuchos::ArrayView<const LO>&, \
1775 size_t, \
1776 CombineMode); \
1777 template size_t \
1778 Details::unpackAndCombineWithOwningPIDsCount<ST, LO, GO, NT>( \
1779 const CrsMatrix<ST, LO, GO, NT>&, \
1780 const Teuchos::ArrayView<const LO>&, \
1781 const Teuchos::ArrayView<const char>&, \
1782 const Teuchos::ArrayView<const size_t>&, \
1783 size_t, \
1784 CombineMode, \
1785 size_t, \
1786 const Teuchos::ArrayView<const LO>&, \
1787 const Teuchos::ArrayView<const LO>&); \
1788 template void \
1789 Details::unpackCrsMatrixAndCombineNew<ST, LO, GO, NT>( \
1790 const CrsMatrix<ST, LO, GO, NT>&, \
1791 Kokkos::DualView<char*, typename DistObject<char, LO, GO, NT>::buffer_device_type>, \
1792 Kokkos::DualView<size_t*, typename DistObject<char, LO, GO, NT>::buffer_device_type>, \
1793 const Kokkos::DualView<const LO*, typename DistObject<char, LO, GO, NT>::buffer_device_type>&, \
1794 const size_t, \
1795 const CombineMode); \
1796 template void \
1797 Details::unpackAndCombineIntoCrsArrays<ST, LO, GO, NT>( \
1798 const CrsMatrix<ST, LO, GO, NT>&, \
1799 const Kokkos::View<LO const*, \
1800 Kokkos::Device<typename NT::device_type::execution_space, \
1801 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>, \
1802 void, void>, \
1803 const Kokkos::View<const char*, \
1804 Kokkos::Device<typename NT::device_type::execution_space, \
1805 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>, \
1806 void, void>, \
1807 const Kokkos::View<const size_t*, \
1808 Kokkos::Device<typename NT::device_type::execution_space, \
1809 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>, \
1810 void, void>, \
1811 const size_t, \
1812 const Kokkos::View<LO const*, \
1813 Kokkos::Device<typename NT::device_type::execution_space, \
1814 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>, \
1815 void, void>, \
1816 const Kokkos::View<LO const*, \
1817 Kokkos::Device<typename NT::device_type::execution_space, \
1818 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>, \
1819 void, void>, \
1820 size_t, \
1821 const int, \
1822 Kokkos::View<size_t*, typename NT::device_type>&, \
1823 Kokkos::View<GO*, typename NT::device_type>&, \
1824 Kokkos::View<typename CrsMatrix<ST, LO, GO, NT>::impl_scalar_type*, typename NT::device_type>&, \
1825 const Teuchos::ArrayView<const int>&, \
1826 Kokkos::View<int*, typename NT::device_type>&); \
1827 template void \
1828 Details::unpackAndCombineIntoCrsArrays<ST, LO, GO, NT>( \
1829 const CrsMatrix<ST, LO, GO, NT>&, \
1830 const Kokkos::View<LO const*, \
1831 Kokkos::Device<typename NT::device_type::execution_space, \
1832 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>, \
1833 void, void>, \
1834 const Kokkos::View<const char*, \
1835 Kokkos::Device<typename NT::device_type::execution_space, \
1836 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>, \
1837 void, void>, \
1838 const Kokkos::View<const size_t*, \
1839 Kokkos::Device<typename NT::device_type::execution_space, \
1840 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>, \
1841 void, void>, \
1842 const size_t, \
1843 const Kokkos::View<LO const*, \
1844 Kokkos::Device<typename NT::device_type::execution_space, \
1845 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>, \
1846 void, void>, \
1847 const Kokkos::View<LO const*, \
1848 Kokkos::Device<typename NT::device_type::execution_space, \
1849 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>, \
1850 void, void>, \
1851 size_t, \
1852 const int, \
1853 Teuchos::ArrayRCP<size_t>&, \
1854 Teuchos::ArrayRCP<GO>&, \
1855 Teuchos::ArrayRCP<ST>&, \
1856 const Teuchos::ArrayView<const int>&, \
1857 Teuchos::Array<int>&);
1858
1859#define TPETRA_DETAILS_UNPACKCRSMATRIXANDCOMBINE_INSTANT_KOKKOS_DEPRECATED_CODE_4_OFF(ST, LO, GO, NT) \
1860 template void \
1861 Details::unpackCrsMatrixAndCombine<ST, LO, GO, NT>( \
1862 const CrsMatrix<ST, LO, GO, NT>&, \
1863 const Teuchos::ArrayView<const char>&, \
1864 const Teuchos::ArrayView<const size_t>&, \
1865 const Teuchos::ArrayView<const LO>&, \
1866 size_t, \
1867 CombineMode); \
1868 template size_t \
1869 Details::unpackAndCombineWithOwningPIDsCount<ST, LO, GO, NT>( \
1870 const CrsMatrix<ST, LO, GO, NT>&, \
1871 const Teuchos::ArrayView<const LO>&, \
1872 const Teuchos::ArrayView<const char>&, \
1873 const Teuchos::ArrayView<const size_t>&, \
1874 size_t, \
1875 CombineMode, \
1876 size_t, \
1877 const Teuchos::ArrayView<const LO>&, \
1878 const Teuchos::ArrayView<const LO>&); \
1879 template void \
1880 Details::unpackCrsMatrixAndCombineNew<ST, LO, GO, NT>( \
1881 const CrsMatrix<ST, LO, GO, NT>&, \
1882 Kokkos::DualView<char*, typename DistObject<char, LO, GO, NT>::buffer_device_type>, \
1883 Kokkos::DualView<size_t*, typename DistObject<char, LO, GO, NT>::buffer_device_type>, \
1884 const Kokkos::DualView<const LO*, typename DistObject<char, LO, GO, NT>::buffer_device_type>&, \
1885 const size_t, \
1886 const CombineMode); \
1887 template void \
1888 Details::unpackAndCombineIntoCrsArrays<ST, LO, GO, NT>( \
1889 const CrsMatrix<ST, LO, GO, NT>&, \
1890 const Kokkos::View<LO const*, \
1891 Kokkos::Device<typename NT::device_type::execution_space, \
1892 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>>, \
1893 const Kokkos::View<const char*, \
1894 Kokkos::Device<typename NT::device_type::execution_space, \
1895 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>>, \
1896 const Kokkos::View<const size_t*, \
1897 Kokkos::Device<typename NT::device_type::execution_space, \
1898 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>>, \
1899 const size_t, \
1900 const Kokkos::View<LO const*, \
1901 Kokkos::Device<typename NT::device_type::execution_space, \
1902 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>>, \
1903 const Kokkos::View<LO const*, \
1904 Kokkos::Device<typename NT::device_type::execution_space, \
1905 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>>, \
1906 size_t, \
1907 const int, \
1908 Kokkos::View<size_t*, typename NT::device_type>&, \
1909 Kokkos::View<GO*, typename NT::device_type>&, \
1910 Kokkos::View<typename CrsMatrix<ST, LO, GO, NT>::impl_scalar_type*, typename NT::device_type>&, \
1911 const Teuchos::ArrayView<const int>&, \
1912 Kokkos::View<int*, typename NT::device_type>&); \
1913 template void \
1914 Details::unpackAndCombineIntoCrsArrays<ST, LO, GO, NT>( \
1915 const CrsMatrix<ST, LO, GO, NT>&, \
1916 const Kokkos::View<LO const*, \
1917 Kokkos::Device<typename NT::device_type::execution_space, \
1918 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>>, \
1919 const Kokkos::View<const char*, \
1920 Kokkos::Device<typename NT::device_type::execution_space, \
1921 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>>, \
1922 const Kokkos::View<const size_t*, \
1923 Kokkos::Device<typename NT::device_type::execution_space, \
1924 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>>, \
1925 const size_t, \
1926 const Kokkos::View<LO const*, \
1927 Kokkos::Device<typename NT::device_type::execution_space, \
1928 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>>, \
1929 const Kokkos::View<LO const*, \
1930 Kokkos::Device<typename NT::device_type::execution_space, \
1931 Tpetra::Details::DefaultTypes::comm_buffer_memory_space<typename NT::device_type>>>, \
1932 size_t, \
1933 const int, \
1934 Teuchos::ArrayRCP<size_t>&, \
1935 Teuchos::ArrayRCP<GO>&, \
1936 Teuchos::ArrayRCP<ST>&, \
1937 const Teuchos::ArrayView<const int>&, \
1938 Teuchos::Array<int>&);
1939
1940#ifdef KOKKOS_ENABLE_DEPRECATED_CODE_4
1941#define TPETRA_DETAILS_UNPACKCRSMATRIXANDCOMBINE_INSTANT(ST, LO, GO, NT) \
1942 TPETRA_DETAILS_UNPACKCRSMATRIXANDCOMBINE_INSTANT_KOKKOS_DEPRECATED_CODE_4_ON(ST, LO, GO, NT)
1943#else
1944#define TPETRA_DETAILS_UNPACKCRSMATRIXANDCOMBINE_INSTANT(ST, LO, GO, NT) \
1945 TPETRA_DETAILS_UNPACKCRSMATRIXANDCOMBINE_INSTANT_KOKKOS_DEPRECATED_CODE_4_OFF(ST, LO, GO, NT)
1946#endif
1947
1948#endif // TPETRA_DETAILS_UNPACKCRSMATRIXANDCOMBINE_DEF_HPP
Declaration of the Tpetra::CrsMatrix class.
Import KokkosSparse::OrdinalTraits, a traits class for "invalid" (flag) values of integer types,...
Declaration and generic definition of traits class that tells Tpetra::CrsMatrix how to pack and unpac...
Declaration and definition of Tpetra::Details::castAwayConstDualView, an implementation detail of Tpe...
Declare and define the functions Tpetra::Details::computeOffsetsFromCounts and Tpetra::computeOffsets...
Functions that wrap Kokkos::create_mirror_view, in order to avoid deep copies when not necessary,...
Declaration and definition of Tpetra::Details::getEntryOnHost.
KOKKOS_FUNCTION int unpackRow(const typename PackTraits< GO >::output_array_type &gids_out, const typename PackTraits< int >::output_array_type &pids_out, const typename PackTraits< ST >::output_array_type &vals_out, const char imports[], const size_t offset, const size_t num_bytes, const size_t num_ent, const size_t bytes_per_value)
Unpack a single row of a CrsMatrix.
int setupRowPointersForRemotes(const typename PackTraits< size_t >::output_array_type &tgt_rowptr, const typename PackTraits< LO >::input_array_type &import_lids, const Kokkos::View< const char *, BDT > &imports, const Kokkos::View< const size_t *, BDT > &num_packets_per_lid, const typename PackTraits< size_t >::input_array_type &offsets)
Setup row pointers for remotes.
size_t compute_total_num_entries(const Kokkos::View< const size_t *, BDT > &num_packets_per_lid, const Kokkos::View< const size_t *, DT > &offsets, const Kokkos::View< const char *, BDT > &imports)
Total number of entries in any row of the packed matrix.
void unpackAndCombineIntoCrsMatrix(const LocalMatrix &local_matrix, const LocalMap &local_map, const Kokkos::View< const char *, BufferDeviceType > &imports, const Kokkos::View< const size_t *, BufferDeviceType > &num_packets_per_lid, const typename PackTraits< typename LocalMap::local_ordinal_type >::input_array_type import_lids, const Tpetra::CombineMode combine_mode)
Perform the unpack operation for the matrix.
size_t compute_maximum_num_entries(const Kokkos::View< const size_t *, BDT > &num_packets_per_lid, const Kokkos::View< const size_t *, DT > &offsets, const Kokkos::View< const char *, BDT > &imports)
Maximum number of entries in any row of the packed matrix.
bool compute_batch_info(const View1 &batches_per_lid, View2 &batch_info)
Compute the index and batch number associated with each batch.
Sparse matrix that presents a row-oriented interface that lets users read or modify entries.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
The communicator over which the matrix is distributed.
TPETRA_DETAILS_ALWAYS_INLINE local_matrix_device_type getLocalMatrixDevice() const
The local sparse matrix.
Teuchos::RCP< const map_type > getColMap() const override
The Map that describes the column distribution in this matrix.
KokkosSparse::CrsMatrix< impl_scalar_type, local_ordinal_type, device_type, void, typename local_graph_device_type::size_type > local_matrix_device_type
The specialization of Kokkos::CrsMatrix that represents the part of the sparse matrix on each MPI pro...
bool isLocallyIndexed() const override
Whether the matrix is locally indexed on the calling process.
typename row_matrix_type::impl_scalar_type impl_scalar_type
The type used internally in place of Scalar.
static size_t hierarchicalUnpackBatchSize()
Size of batch for hierarchical unpacking.
static size_t hierarchicalUnpackTeamSize()
Size of team for hierarchical unpacking.
"Local" part of Map suitable for Kokkos kernels.
LocalOrdinal local_ordinal_type
The type of local indices.
GlobalOrdinal global_ordinal_type
The type of global indices.
DeviceType device_type
The device type.
Kokkos::parallel_reduce functor to determine the number of entries (to unpack) in a KokkosSparse::Crs...
Base class for distributed Tpetra objects that support data redistribution.
Kokkos::Device< typename device_type::execution_space, buffer_memory_space > buffer_device_type
Kokkos::Device specialization for communication buffers.
Nonmember function that computes a residual Computes R = B - A * X.
void unpackAndCombineIntoCrsArrays(const CrsGraph< LO, GO, NT > &sourceGraph, const Teuchos::ArrayView< const LO > &importLIDs, const Teuchos::ArrayView< const typename CrsGraph< LO, GO, NT >::packet_type > &imports, const Teuchos::ArrayView< const size_t > &numPacketsPerLID, const size_t constantNumPackets, const CombineMode combineMode, const size_t numSameIDs, const Teuchos::ArrayView< const LO > &permuteToLIDs, const Teuchos::ArrayView< const LO > &permuteFromLIDs, size_t TargetNumRows, size_t TargetNumNonzeros, const int MyTargetPID, const Teuchos::ArrayView< size_t > &CRS_rowptr, const Teuchos::ArrayView< GO > &CRS_colind, const Teuchos::ArrayView< const int > &SourcePids, Teuchos::Array< int > &TargetPids)
unpackAndCombineIntoCrsArrays
Impl::CreateMirrorViewFromUnmanagedHostArray< ValueType, OutputDeviceType >::output_view_type create_mirror_view_from_raw_host_array(const OutputDeviceType &, ValueType *inPtr, const size_t inSize, const bool copy=true, const char label[]="")
Variant of Kokkos::create_mirror_view that takes a raw host 1-d array as input.
size_t unpackAndCombineWithOwningPIDsCount(const CrsGraph< LO, GO, NT > &sourceGraph, const Teuchos::ArrayView< const LO > &importLIDs, const Teuchos::ArrayView< const typename CrsGraph< LO, GO, NT >::packet_type > &imports, const Teuchos::ArrayView< const size_t > &numPacketsPerLID, size_t constantNumPackets, CombineMode combineMode, size_t numSameIDs, const Teuchos::ArrayView< const LO > &permuteToLIDs, const Teuchos::ArrayView< const LO > &permuteFromLIDs)
Special version of Tpetra::Details::unpackCrsGraphAndCombine that also unpacks owning process ranks.
void unpackCrsMatrixAndCombine(const CrsMatrix< ST, LO, GO, NT > &sourceMatrix, const Teuchos::ArrayView< const char > &imports, const Teuchos::ArrayView< const size_t > &numPacketsPerLID, const Teuchos::ArrayView< const LO > &importLIDs, size_t constantNumPackets, CombineMode combineMode)
Unpack the imported column indices and values, and combine into matrix.
OffsetsViewType::non_const_value_type computeOffsetsFromCounts(const ExecutionSpace &execSpace, const OffsetsViewType &ptr, const CountsViewType &counts)
Compute offsets from counts.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
void deep_copy(MultiVector< DS, DL, DG, DN > &dst, const MultiVector< SS, SL, SG, SN > &src)
Copy the contents of the MultiVector src into dst.
CombineMode
Rule for combining data in an Import or Export.
@ REPLACE
Replace existing values with new values.
@ ADD
Sum new values.
@ ABSMAX
Replace old value with maximum of magnitudes of old and new values.
@ INSERT
Insert new values that don't currently exist.
Traits class for packing / unpacking data of type T.
static KOKKOS_INLINE_FUNCTION Kokkos::pair< int, size_t > unpackArray(value_type outBuf[], const char inBuf[], const size_t numEnt)
Unpack numEnt value_type entries from the given input buffer of bytes, to the given output buffer of ...
static KOKKOS_INLINE_FUNCTION size_t unpackValue(T &outVal, const char inBuf[])
Unpack the given value from the given output buffer.
Kokkos::View< value_type *, Kokkos::AnonymousSpace > output_array_type
The type of an output array of value_type.
static const bool compileTimeSize
Whether the number of bytes required to pack one instance of value_type is fixed at compile time.
static KOKKOS_INLINE_FUNCTION size_t packValueCount(const T &)
Number of bytes required to pack or unpack the given value of type value_type.
Kokkos::View< const value_type *, Kokkos::AnonymousSpace > input_array_type
The type of an input array of value_type.