22 #ifndef TPETRA_KOKKOS_REFACTOR_DETAILS_MULTI_VECTOR_DIST_OBJECT_KERNELS_HPP
23 #define TPETRA_KOKKOS_REFACTOR_DETAILS_MULTI_VECTOR_DIST_OBJECT_KERNELS_HPP
25 #include "Kokkos_Core.hpp"
26 #if KOKKOS_VERSION >= 40799
27 #include "KokkosKernels_ArithTraits.hpp"
29 #include "Kokkos_ArithTraits.hpp"
35 namespace KokkosRefactor {
51 template <
class IntegerType,
52 const bool isSigned = std::numeric_limits<IntegerType>::is_signed>
54 static KOKKOS_INLINE_FUNCTION
bool
55 test(
const IntegerType x,
56 const IntegerType exclusiveUpperBound);
60 template <
class IntegerType>
62 static KOKKOS_INLINE_FUNCTION
bool
63 test(
const IntegerType x,
64 const IntegerType exclusiveUpperBound) {
65 return x < static_cast<IntegerType>(0) || x >= exclusiveUpperBound;
70 template <
class IntegerType>
71 struct OutOfBounds<IntegerType, false> {
72 static KOKKOS_INLINE_FUNCTION
bool
73 test(
const IntegerType x,
74 const IntegerType exclusiveUpperBound) {
75 return x >= exclusiveUpperBound;
81 template <
class IntegerType>
82 KOKKOS_INLINE_FUNCTION
bool
83 outOfBounds(
const IntegerType x,
const IntegerType exclusiveUpperBound) {
92 template <
typename DstView,
typename SrcView,
typename IdxView,
93 typename Enabled =
void>
94 struct PackArraySingleColumn {
95 typedef typename DstView::execution_space execution_space;
96 typedef typename execution_space::size_type size_type;
103 PackArraySingleColumn(
const DstView& dst_,
112 KOKKOS_INLINE_FUNCTION
void
113 operator()(
const size_type k)
const {
114 dst(k) = src(idx(k), col);
118 pack(
const DstView& dst,
122 const execution_space& space) {
123 typedef Kokkos::RangePolicy<execution_space, size_type> range_type;
124 Kokkos::parallel_for(
"Tpetra::MultiVector pack one col",
125 range_type(space, 0, idx.size()),
126 PackArraySingleColumn(dst, src, idx, col));
130 template <
typename DstView,
133 typename SizeType =
typename DstView::execution_space::size_type,
134 typename Enabled =
void>
135 class PackArraySingleColumnWithBoundsCheck {
137 static_assert(Kokkos::is_view<DstView>::value,
138 "DstView must be a Kokkos::View.");
139 static_assert(Kokkos::is_view<SrcView>::value,
140 "SrcView must be a Kokkos::View.");
141 static_assert(Kokkos::is_view<IdxView>::value,
142 "IdxView must be a Kokkos::View.");
143 static_assert(static_cast<int>(DstView::rank) == 1,
144 "DstView must be a rank-1 Kokkos::View.");
145 static_assert(static_cast<int>(SrcView::rank) == 2,
146 "SrcView must be a rank-2 Kokkos::View.");
147 static_assert(static_cast<int>(IdxView::rank) == 1,
148 "IdxView must be a rank-1 Kokkos::View.");
149 static_assert(std::is_integral<SizeType>::value,
150 "SizeType must be a built-in integer type.");
152 using execution_space =
typename DstView::execution_space;
155 typedef SizeType size_type;
156 using value_type = size_t;
163 execution_space space;
166 PackArraySingleColumnWithBoundsCheck(
const DstView& dst_,
169 const size_type col_)
175 KOKKOS_INLINE_FUNCTION
void
176 operator()(
const size_type k, value_type& lclErrCount)
const {
177 using index_type =
typename IdxView::non_const_value_type;
179 const index_type lclRow = idx(k);
180 if (lclRow < static_cast<index_type>(0) ||
181 lclRow >= static_cast<index_type>(src.extent(0))) {
184 dst(k) = src(lclRow, col);
188 KOKKOS_INLINE_FUNCTION
189 void init(value_type& initialErrorCount)
const {
190 initialErrorCount = 0;
193 KOKKOS_INLINE_FUNCTION
void
194 join(value_type& dstErrorCount,
195 const value_type& srcErrorCount)
const {
196 dstErrorCount += srcErrorCount;
200 pack(
const DstView& dst,
204 const execution_space& space) {
205 typedef Kokkos::RangePolicy<execution_space, size_type> range_type;
206 typedef typename IdxView::non_const_value_type index_type;
208 size_t errorCount = 0;
209 Kokkos::parallel_reduce(
"Tpetra::MultiVector pack one col debug only",
210 range_type(space, 0, idx.size()),
211 PackArraySingleColumnWithBoundsCheck(dst, src, idx, col),
214 if (errorCount != 0) {
218 auto idx_h = Kokkos::create_mirror_view(idx);
223 std::vector<index_type> badIndices;
224 const size_type numInds = idx_h.extent(0);
225 for (size_type k = 0; k < numInds; ++k) {
226 if (idx_h(k) < static_cast<index_type>(0) ||
227 idx_h(k) >= static_cast<index_type>(src.extent(0))) {
228 badIndices.push_back(idx_h(k));
232 TEUCHOS_TEST_FOR_EXCEPTION(errorCount != badIndices.size(), std::logic_error,
233 "PackArraySingleColumnWithBoundsCheck: errorCount = " << errorCount
234 <<
" != badIndices.size() = " << badIndices.size() <<
". This sho"
235 "uld never happen. Please report this to the Tpetra developers.");
237 std::ostringstream os;
238 os <<
"MultiVector single-column pack kernel had "
239 << badIndices.size() <<
" out-of bounds index/ices. "
241 for (
size_t k = 0; k < badIndices.size(); ++k) {
243 if (k + 1 < badIndices.size()) {
248 throw std::runtime_error(os.str());
253 template <
typename DstView,
typename SrcView,
typename IdxView>
254 void pack_array_single_column(
const DstView& dst,
259 const typename DstView::execution_space& space) {
260 static_assert(Kokkos::is_view<DstView>::value,
261 "DstView must be a Kokkos::View.");
262 static_assert(Kokkos::is_view<SrcView>::value,
263 "SrcView must be a Kokkos::View.");
264 static_assert(Kokkos::is_view<IdxView>::value,
265 "IdxView must be a Kokkos::View.");
266 static_assert(static_cast<int>(DstView::rank) == 1,
267 "DstView must be a rank-1 Kokkos::View.");
268 static_assert(static_cast<int>(SrcView::rank) == 2,
269 "SrcView must be a rank-2 Kokkos::View.");
270 static_assert(static_cast<int>(IdxView::rank) == 1,
271 "IdxView must be a rank-1 Kokkos::View.");
273 using execution_space =
typename DstView::execution_space;
275 static_assert(Kokkos::SpaceAccessibility<execution_space,
276 typename DstView::memory_space>::accessible,
277 "DstView not accessible from execution space");
278 static_assert(Kokkos::SpaceAccessibility<execution_space,
279 typename SrcView::memory_space>::accessible,
280 "SrcView not accessible from execution space");
281 static_assert(Kokkos::SpaceAccessibility<execution_space,
282 typename IdxView::memory_space>::accessible,
283 "IdxView not accessible from execution space");
286 typedef PackArraySingleColumnWithBoundsCheck<DstView, SrcView, IdxView> impl_type;
287 impl_type::pack(dst, src, idx, col, space);
289 typedef PackArraySingleColumn<DstView, SrcView, IdxView> impl_type;
290 impl_type::pack(dst, src, idx, col, space);
296 template <
typename DstView,
typename SrcView,
typename IdxView>
297 void pack_array_single_column(
const DstView& dst,
301 const bool debug =
true) {
302 pack_array_single_column(dst, src, idx, col, debug,
typename DstView::execution_space());
305 template <
typename DstView,
typename SrcView,
typename IdxView,
306 typename Enabled =
void>
307 struct PackArrayMultiColumn {
308 using execution_space =
typename DstView::execution_space;
309 typedef typename execution_space::size_type size_type;
316 PackArrayMultiColumn(
const DstView& dst_,
319 const size_t numCols_)
323 , numCols(numCols_) {}
325 KOKKOS_INLINE_FUNCTION
void
326 operator()(
const size_type k)
const {
327 const typename IdxView::value_type localRow = idx(k);
328 const size_t offset = k * numCols;
329 for (
size_t j = 0; j < numCols; ++j) {
330 dst(offset + j) = src(localRow, j);
334 static void pack(
const DstView& dst,
338 const execution_space& space) {
339 typedef Kokkos::RangePolicy<execution_space, size_type> range_type;
340 Kokkos::parallel_for(
"Tpetra::MultiVector pack multicol const stride",
341 range_type(space, 0, idx.size()),
342 PackArrayMultiColumn(dst, src, idx, numCols));
346 template <
typename DstView,
349 typename SizeType =
typename DstView::execution_space::size_type,
350 typename Enabled =
void>
351 class PackArrayMultiColumnWithBoundsCheck {
353 using size_type = SizeType;
354 using value_type = size_t;
355 using execution_space =
typename DstView::execution_space;
364 PackArrayMultiColumnWithBoundsCheck(
const DstView& dst_,
367 const size_type numCols_)
371 , numCols(numCols_) {}
373 KOKKOS_INLINE_FUNCTION
void
374 operator()(
const size_type k, value_type& lclErrorCount)
const {
375 typedef typename IdxView::non_const_value_type index_type;
377 const index_type lclRow = idx(k);
378 if (lclRow < static_cast<index_type>(0) ||
379 lclRow >= static_cast<index_type>(src.extent(0))) {
382 const size_type offset = k * numCols;
383 for (size_type j = 0; j < numCols; ++j) {
384 dst(offset + j) = src(lclRow, j);
389 KOKKOS_INLINE_FUNCTION
390 void init(value_type& initialErrorCount)
const {
391 initialErrorCount = 0;
394 KOKKOS_INLINE_FUNCTION
void
395 join(value_type& dstErrorCount,
396 const value_type& srcErrorCount)
const {
397 dstErrorCount += srcErrorCount;
401 pack(
const DstView& dst,
404 const size_type numCols,
405 const execution_space& space) {
406 typedef Kokkos::RangePolicy<execution_space, size_type> range_type;
407 typedef typename IdxView::non_const_value_type index_type;
409 size_t errorCount = 0;
410 Kokkos::parallel_reduce(
"Tpetra::MultiVector pack multicol const stride debug only",
411 range_type(space, 0, idx.size()),
412 PackArrayMultiColumnWithBoundsCheck(dst, src, idx, numCols),
414 if (errorCount != 0) {
418 auto idx_h = Kokkos::create_mirror_view(idx);
423 std::vector<index_type> badIndices;
424 const size_type numInds = idx_h.extent(0);
425 for (size_type k = 0; k < numInds; ++k) {
426 if (idx_h(k) < static_cast<index_type>(0) ||
427 idx_h(k) >= static_cast<index_type>(src.extent(0))) {
428 badIndices.push_back(idx_h(k));
432 TEUCHOS_TEST_FOR_EXCEPTION(errorCount != badIndices.size(), std::logic_error,
433 "PackArrayMultiColumnWithBoundsCheck: errorCount = " << errorCount
434 <<
" != badIndices.size() = " << badIndices.size() <<
". This sho"
435 "uld never happen. Please report this to the Tpetra developers.");
437 std::ostringstream os;
438 os <<
"Tpetra::MultiVector multiple-column pack kernel had "
439 << badIndices.size() <<
" out-of bounds index/ices (errorCount = "
440 << errorCount <<
"): [";
441 for (
size_t k = 0; k < badIndices.size(); ++k) {
443 if (k + 1 < badIndices.size()) {
448 throw std::runtime_error(os.str());
453 template <
typename DstView,
456 void pack_array_multi_column(
const DstView& dst,
459 const size_t numCols,
461 const typename DstView::execution_space& space) {
462 static_assert(Kokkos::is_view<DstView>::value,
463 "DstView must be a Kokkos::View.");
464 static_assert(Kokkos::is_view<SrcView>::value,
465 "SrcView must be a Kokkos::View.");
466 static_assert(Kokkos::is_view<IdxView>::value,
467 "IdxView must be a Kokkos::View.");
468 static_assert(static_cast<int>(DstView::rank) == 1,
469 "DstView must be a rank-1 Kokkos::View.");
470 static_assert(static_cast<int>(SrcView::rank) == 2,
471 "SrcView must be a rank-2 Kokkos::View.");
472 static_assert(static_cast<int>(IdxView::rank) == 1,
473 "IdxView must be a rank-1 Kokkos::View.");
475 using execution_space =
typename DstView::execution_space;
477 static_assert(Kokkos::SpaceAccessibility<execution_space,
478 typename DstView::memory_space>::accessible,
479 "DstView not accessible from execution space");
480 static_assert(Kokkos::SpaceAccessibility<execution_space,
481 typename SrcView::memory_space>::accessible,
482 "SrcView not accessible from execution space");
483 static_assert(Kokkos::SpaceAccessibility<execution_space,
484 typename IdxView::memory_space>::accessible,
485 "IdxView not accessible from execution space");
488 typedef PackArrayMultiColumnWithBoundsCheck<DstView,
491 impl_type::pack(dst, src, idx, numCols, space);
493 typedef PackArrayMultiColumn<DstView, SrcView, IdxView> impl_type;
494 impl_type::pack(dst, src, idx, numCols, space);
498 template <
typename DstView,
501 void pack_array_multi_column(
const DstView& dst,
504 const size_t numCols,
505 const bool debug =
true) {
506 pack_array_multi_column(dst, src, idx, numCols, debug,
typename DstView::execution_space());
509 template <
typename DstView,
typename SrcView,
typename IdxView,
510 typename ColView,
typename Enabled =
void>
511 struct PackArrayMultiColumnVariableStride {
512 using execution_space =
typename DstView::execution_space;
513 typedef typename execution_space::size_type size_type;
521 PackArrayMultiColumnVariableStride(
const DstView& dst_,
525 const size_t numCols_)
530 , numCols(numCols_) {}
532 KOKKOS_INLINE_FUNCTION
533 void operator()(
const size_type k)
const {
534 const typename IdxView::value_type localRow = idx(k);
535 const size_t offset = k * numCols;
536 for (
size_t j = 0; j < numCols; ++j) {
537 dst(offset + j) = src(localRow, col(j));
541 static void pack(
const DstView& dst,
546 const execution_space& space) {
547 typedef Kokkos::RangePolicy<execution_space, size_type> range_type;
548 Kokkos::parallel_for(
"Tpetra::MultiVector pack multicol var stride",
549 range_type(space, 0, idx.size()),
550 PackArrayMultiColumnVariableStride(dst, src, idx, col, numCols));
554 template <
typename DstView,
558 typename SizeType =
typename DstView::execution_space::size_type,
559 typename Enabled =
void>
560 class PackArrayMultiColumnVariableStrideWithBoundsCheck {
562 using size_type = SizeType;
563 using value_type = size_t;
564 using execution_space =
typename DstView::execution_space;
574 PackArrayMultiColumnVariableStrideWithBoundsCheck(
const DstView& dst_,
578 const size_type numCols_)
583 , numCols(numCols_) {}
585 KOKKOS_INLINE_FUNCTION
void
586 operator()(
const size_type k, value_type& lclErrorCount)
const {
587 typedef typename IdxView::non_const_value_type row_index_type;
588 typedef typename ColView::non_const_value_type col_index_type;
590 const row_index_type lclRow = idx(k);
591 if (lclRow < static_cast<row_index_type>(0) ||
592 lclRow >= static_cast<row_index_type>(src.extent(0))) {
595 const size_type offset = k * numCols;
596 for (size_type j = 0; j < numCols; ++j) {
597 const col_index_type lclCol = col(j);
598 if (Impl::outOfBounds<col_index_type>(lclCol, src.extent(1))) {
601 dst(offset + j) = src(lclRow, lclCol);
607 KOKKOS_INLINE_FUNCTION
void
608 init(value_type& initialErrorCount)
const {
609 initialErrorCount = 0;
612 KOKKOS_INLINE_FUNCTION
void
613 join(value_type& dstErrorCount,
614 const value_type& srcErrorCount)
const {
615 dstErrorCount += srcErrorCount;
619 pack(
const DstView& dst,
623 const size_type numCols,
624 const execution_space& space) {
625 using range_type = Kokkos::RangePolicy<execution_space, size_type>;
626 using row_index_type =
typename IdxView::non_const_value_type;
627 using col_index_type =
typename ColView::non_const_value_type;
629 size_t errorCount = 0;
630 Kokkos::parallel_reduce(
"Tpetra::MultiVector pack multicol var stride debug only",
631 range_type(space, 0, idx.size()),
632 PackArrayMultiColumnVariableStrideWithBoundsCheck(dst, src, idx,
635 if (errorCount != 0) {
636 constexpr
size_t maxNumBadIndicesToPrint = 100;
638 std::ostringstream os;
639 os <<
"Tpetra::MultiVector multicolumn variable stride pack kernel "
642 <<
" error" << (errorCount != size_t(1) ?
"s" :
"") <<
". ";
647 auto idx_h = Kokkos::create_mirror_view(idx);
652 std::vector<row_index_type> badRows;
653 const size_type numRowInds = idx_h.extent(0);
654 for (size_type k = 0; k < numRowInds; ++k) {
655 if (Impl::outOfBounds<row_index_type>(idx_h(k), src.extent(0))) {
656 badRows.push_back(idx_h(k));
660 if (badRows.size() != 0) {
661 os << badRows.size() <<
" out-of-bounds row ind"
662 << (badRows.size() != size_t(1) ?
"ices" :
"ex");
663 if (badRows.size() <= maxNumBadIndicesToPrint) {
665 for (
size_t k = 0; k < badRows.size(); ++k) {
667 if (k + 1 < badRows.size()) {
676 os <<
"No out-of-bounds row indices. ";
681 auto col_h = Kokkos::create_mirror_view(col);
686 std::vector<col_index_type> badCols;
687 const size_type numColInds = col_h.extent(0);
688 for (size_type k = 0; k < numColInds; ++k) {
689 if (Impl::outOfBounds<col_index_type>(col_h(k), src.extent(1))) {
690 badCols.push_back(col_h(k));
694 if (badCols.size() != 0) {
695 os << badCols.size() <<
" out-of-bounds column ind"
696 << (badCols.size() != size_t(1) ?
"ices" :
"ex");
697 if (badCols.size() <= maxNumBadIndicesToPrint) {
699 for (
size_t k = 0; k < badCols.size(); ++k) {
701 if (k + 1 < badCols.size()) {
710 os <<
"No out-of-bounds column indices. ";
713 TEUCHOS_TEST_FOR_EXCEPTION(errorCount != 0 && badRows.size() == 0 && badCols.size() == 0,
715 "Tpetra::MultiVector variable stride pack "
716 "kernel reports errorCount="
717 << errorCount <<
", but we failed "
718 "to find any bad rows or columns. This should never happen. "
719 "Please report this to the Tpetra developers.");
721 throw std::runtime_error(os.str());
726 template <
typename DstView,
730 void pack_array_multi_column_variable_stride(
const DstView& dst,
734 const size_t numCols,
736 const typename DstView::execution_space& space) {
737 static_assert(Kokkos::is_view<DstView>::value,
738 "DstView must be a Kokkos::View.");
739 static_assert(Kokkos::is_view<SrcView>::value,
740 "SrcView must be a Kokkos::View.");
741 static_assert(Kokkos::is_view<IdxView>::value,
742 "IdxView must be a Kokkos::View.");
743 static_assert(Kokkos::is_view<ColView>::value,
744 "ColView must be a Kokkos::View.");
745 static_assert(static_cast<int>(DstView::rank) == 1,
746 "DstView must be a rank-1 Kokkos::View.");
747 static_assert(static_cast<int>(SrcView::rank) == 2,
748 "SrcView must be a rank-2 Kokkos::View.");
749 static_assert(static_cast<int>(IdxView::rank) == 1,
750 "IdxView must be a rank-1 Kokkos::View.");
751 static_assert(static_cast<int>(ColView::rank) == 1,
752 "ColView must be a rank-1 Kokkos::View.");
754 using execution_space =
typename DstView::execution_space;
756 static_assert(Kokkos::SpaceAccessibility<execution_space,
757 typename DstView::memory_space>::accessible,
758 "DstView not accessible from execution space");
759 static_assert(Kokkos::SpaceAccessibility<execution_space,
760 typename SrcView::memory_space>::accessible,
761 "SrcView not accessible from execution space");
762 static_assert(Kokkos::SpaceAccessibility<execution_space,
763 typename IdxView::memory_space>::accessible,
764 "IdxView not accessible from execution space");
767 typedef PackArrayMultiColumnVariableStrideWithBoundsCheck<DstView,
768 SrcView, IdxView, ColView>
770 impl_type::pack(dst, src, idx, col, numCols, space);
772 typedef PackArrayMultiColumnVariableStride<DstView,
773 SrcView, IdxView, ColView>
775 impl_type::pack(dst, src, idx, col, numCols, space);
779 template <
typename DstView,
783 void pack_array_multi_column_variable_stride(
const DstView& dst,
787 const size_t numCols,
788 const bool debug =
true) {
789 pack_array_multi_column_variable_stride(dst, src, idx, col, numCols, debug,
790 typename DstView::execution_space());
795 struct atomic_tag {};
796 struct nonatomic_tag {};
800 KOKKOS_INLINE_FUNCTION
void operator()(atomic_tag, SC& dest,
const SC& src)
const {
801 Kokkos::atomic_add(&dest, src);
805 KOKKOS_INLINE_FUNCTION
void operator()(nonatomic_tag, SC& dest,
const SC& src)
const {
816 KOKKOS_INLINE_FUNCTION
void operator()(atomic_tag, SC& dest,
const SC& src)
const {
821 KOKKOS_INLINE_FUNCTION
void operator()(nonatomic_tag, SC& dest,
const SC& src)
const {
827 template <
class Scalar>
828 struct AbsMaxHelper {
831 KOKKOS_FUNCTION AbsMaxHelper& operator+=(AbsMaxHelper
const& rhs) {
832 #if KOKKOS_VERSION >= 40799
833 auto lhs_abs_value = KokkosKernels::ArithTraits<Scalar>::abs(value);
835 auto lhs_abs_value = Kokkos::ArithTraits<Scalar>::abs(value);
837 #if KOKKOS_VERSION >= 40799
838 auto rhs_abs_value = KokkosKernels::ArithTraits<Scalar>::abs(rhs.value);
840 auto rhs_abs_value = Kokkos::ArithTraits<Scalar>::abs(rhs.value);
842 value = lhs_abs_value > rhs_abs_value ? lhs_abs_value : rhs_abs_value;
846 KOKKOS_FUNCTION AbsMaxHelper operator+(AbsMaxHelper
const& rhs)
const {
847 AbsMaxHelper ret = *
this;
853 template <
typename SC>
854 KOKKOS_INLINE_FUNCTION
void operator()(atomic_tag, SC& dst,
const SC& src)
const {
855 Kokkos::atomic_add(
reinterpret_cast<AbsMaxHelper<SC>*
>(&dst), AbsMaxHelper<SC>{src});
858 template <
typename SC>
859 KOKKOS_INLINE_FUNCTION
void operator()(nonatomic_tag, SC& dst,
const SC& src)
const {
860 #if KOKKOS_VERSION >= 40799
861 auto dst_abs_value = KokkosKernels::ArithTraits<SC>::abs(dst);
863 auto dst_abs_value = Kokkos::ArithTraits<SC>::abs(dst);
865 #if KOKKOS_VERSION >= 40799
866 auto src_abs_value = KokkosKernels::ArithTraits<SC>::abs(src);
868 auto src_abs_value = Kokkos::ArithTraits<SC>::abs(src);
870 dst = dst_abs_value > src_abs_value ? dst_abs_value : src_abs_value;
874 template <
typename ExecutionSpace,
879 typename Enabled =
void>
880 class UnpackArrayMultiColumn {
882 static_assert(Kokkos::is_view<DstView>::value,
883 "DstView must be a Kokkos::View.");
884 static_assert(Kokkos::is_view<SrcView>::value,
885 "SrcView must be a Kokkos::View.");
886 static_assert(Kokkos::is_view<IdxView>::value,
887 "IdxView must be a Kokkos::View.");
888 static_assert(static_cast<int>(DstView::rank) == 2,
889 "DstView must be a rank-2 Kokkos::View.");
890 static_assert(static_cast<int>(SrcView::rank) == 1,
891 "SrcView must be a rank-1 Kokkos::View.");
892 static_assert(static_cast<int>(IdxView::rank) == 1,
893 "IdxView must be a rank-1 Kokkos::View.");
896 typedef typename ExecutionSpace::execution_space execution_space;
897 typedef typename execution_space::size_type size_type;
907 UnpackArrayMultiColumn(
const ExecutionSpace& ,
912 const size_t numCols_)
917 , numCols(numCols_) {}
919 template <
class TagType>
920 KOKKOS_INLINE_FUNCTION
void
921 operator()(TagType tag,
const size_type k)
const {
922 static_assert(std::is_same<TagType, atomic_tag>::value ||
923 std::is_same<TagType, nonatomic_tag>::value,
924 "TagType must be atomic_tag or nonatomic_tag.");
926 const typename IdxView::value_type localRow = idx(k);
927 const size_t offset = k * numCols;
928 for (
size_t j = 0; j < numCols; ++j) {
929 op(tag, dst(localRow, j), src(offset + j));
934 unpack(
const ExecutionSpace& execSpace,
939 const size_t numCols,
940 const bool use_atomic_updates) {
941 if (use_atomic_updates) {
943 Kokkos::RangePolicy<atomic_tag, execution_space, size_type>;
944 Kokkos::parallel_for(
"Tpetra::MultiVector unpack const stride atomic",
945 range_type(0, idx.size()),
946 UnpackArrayMultiColumn(execSpace, dst, src, idx, op, numCols));
949 Kokkos::RangePolicy<nonatomic_tag, execution_space, size_type>;
950 Kokkos::parallel_for(
"Tpetra::MultiVector unpack const stride nonatomic",
951 range_type(0, idx.size()),
952 UnpackArrayMultiColumn(execSpace, dst, src, idx, op, numCols));
957 template <
typename ExecutionSpace,
962 typename SizeType =
typename ExecutionSpace::execution_space::size_type,
963 typename Enabled =
void>
964 class UnpackArrayMultiColumnWithBoundsCheck {
966 static_assert(Kokkos::is_view<DstView>::value,
967 "DstView must be a Kokkos::View.");
968 static_assert(Kokkos::is_view<SrcView>::value,
969 "SrcView must be a Kokkos::View.");
970 static_assert(Kokkos::is_view<IdxView>::value,
971 "IdxView must be a Kokkos::View.");
972 static_assert(static_cast<int>(DstView::rank) == 2,
973 "DstView must be a rank-2 Kokkos::View.");
974 static_assert(static_cast<int>(SrcView::rank) == 1,
975 "SrcView must be a rank-1 Kokkos::View.");
976 static_assert(static_cast<int>(IdxView::rank) == 1,
977 "IdxView must be a rank-1 Kokkos::View.");
978 static_assert(std::is_integral<SizeType>::value,
979 "SizeType must be a built-in integer type.");
982 using execution_space =
typename ExecutionSpace::execution_space;
983 using size_type = SizeType;
984 using value_type = size_t;
994 UnpackArrayMultiColumnWithBoundsCheck(
const ExecutionSpace& ,
999 const size_type numCols_)
1004 , numCols(numCols_) {}
1006 template <
class TagType>
1007 KOKKOS_INLINE_FUNCTION
void
1008 operator()(TagType tag,
1010 size_t& lclErrCount)
const {
1011 static_assert(std::is_same<TagType, atomic_tag>::value ||
1012 std::is_same<TagType, nonatomic_tag>::value,
1013 "TagType must be atomic_tag or nonatomic_tag.");
1014 using index_type =
typename IdxView::non_const_value_type;
1016 const index_type lclRow = idx(k);
1017 if (lclRow < static_cast<index_type>(0) ||
1018 lclRow >= static_cast<index_type>(dst.extent(0))) {
1021 const size_type offset = k * numCols;
1022 for (size_type j = 0; j < numCols; ++j) {
1023 op(tag, dst(lclRow, j), src(offset + j));
1028 template <
class TagType>
1029 KOKKOS_INLINE_FUNCTION
void
1030 init(TagType,
size_t& initialErrorCount)
const {
1031 initialErrorCount = 0;
1034 template <
class TagType>
1035 KOKKOS_INLINE_FUNCTION
void
1037 size_t& dstErrorCount,
1038 const size_t& srcErrorCount)
const {
1039 dstErrorCount += srcErrorCount;
1043 unpack(
const ExecutionSpace& execSpace,
1048 const size_type numCols,
1049 const bool use_atomic_updates) {
1050 using index_type =
typename IdxView::non_const_value_type;
1052 size_t errorCount = 0;
1053 if (use_atomic_updates) {
1055 Kokkos::RangePolicy<atomic_tag, execution_space, size_type>;
1056 Kokkos::parallel_reduce(
"Tpetra::MultiVector unpack multicol const stride atomic debug only",
1057 range_type(0, idx.size()),
1058 UnpackArrayMultiColumnWithBoundsCheck(execSpace, dst, src,
1063 Kokkos::RangePolicy<nonatomic_tag, execution_space, size_type>;
1064 Kokkos::parallel_reduce(
"Tpetra::MultiVector unpack multicol const stride nonatomic debug only",
1065 range_type(0, idx.size()),
1066 UnpackArrayMultiColumnWithBoundsCheck(execSpace, dst, src,
1071 if (errorCount != 0) {
1075 auto idx_h = Kokkos::create_mirror_view(idx);
1080 std::vector<index_type> badIndices;
1081 const size_type numInds = idx_h.extent(0);
1082 for (size_type k = 0; k < numInds; ++k) {
1083 if (idx_h(k) < static_cast<index_type>(0) ||
1084 idx_h(k) >= static_cast<index_type>(dst.extent(0))) {
1085 badIndices.push_back(idx_h(k));
1089 if (errorCount != badIndices.size()) {
1090 std::ostringstream os;
1091 os <<
"MultiVector unpack kernel: errorCount = " << errorCount
1092 <<
" != badIndices.size() = " << badIndices.size()
1093 <<
". This should never happen. "
1094 "Please report this to the Tpetra developers.";
1095 throw std::logic_error(os.str());
1098 std::ostringstream os;
1099 os <<
"MultiVector unpack kernel had " << badIndices.size()
1100 <<
" out-of bounds index/ices. Here they are: [";
1101 for (
size_t k = 0; k < badIndices.size(); ++k) {
1102 os << badIndices[k];
1103 if (k + 1 < badIndices.size()) {
1108 throw std::runtime_error(os.str());
1113 template <
typename ExecutionSpace,
1118 void unpack_array_multi_column(
const ExecutionSpace& execSpace,
1123 const size_t numCols,
1124 const bool use_atomic_updates,
1126 static_assert(Kokkos::is_view<DstView>::value,
1127 "DstView must be a Kokkos::View.");
1128 static_assert(Kokkos::is_view<SrcView>::value,
1129 "SrcView must be a Kokkos::View.");
1130 static_assert(Kokkos::is_view<IdxView>::value,
1131 "IdxView must be a Kokkos::View.");
1132 static_assert(static_cast<int>(DstView::rank) == 2,
1133 "DstView must be a rank-2 Kokkos::View.");
1134 static_assert(static_cast<int>(SrcView::rank) == 1,
1135 "SrcView must be a rank-1 Kokkos::View.");
1136 static_assert(static_cast<int>(IdxView::rank) == 1,
1137 "IdxView must be a rank-1 Kokkos::View.");
1140 typedef UnpackArrayMultiColumnWithBoundsCheck<ExecutionSpace,
1141 DstView, SrcView, IdxView, Op>
1143 impl_type::unpack(execSpace, dst, src, idx, op, numCols,
1144 use_atomic_updates);
1146 typedef UnpackArrayMultiColumn<ExecutionSpace,
1147 DstView, SrcView, IdxView, Op>
1149 impl_type::unpack(execSpace, dst, src, idx, op, numCols,
1150 use_atomic_updates);
1154 template <
typename ExecutionSpace,
1160 typename Enabled =
void>
1161 class UnpackArrayMultiColumnVariableStride {
1163 static_assert(Kokkos::is_view<DstView>::value,
1164 "DstView must be a Kokkos::View.");
1165 static_assert(Kokkos::is_view<SrcView>::value,
1166 "SrcView must be a Kokkos::View.");
1167 static_assert(Kokkos::is_view<IdxView>::value,
1168 "IdxView must be a Kokkos::View.");
1169 static_assert(Kokkos::is_view<ColView>::value,
1170 "ColView must be a Kokkos::View.");
1171 static_assert(static_cast<int>(DstView::rank) == 2,
1172 "DstView must be a rank-2 Kokkos::View.");
1173 static_assert(static_cast<int>(SrcView::rank) == 1,
1174 "SrcView must be a rank-1 Kokkos::View.");
1175 static_assert(static_cast<int>(IdxView::rank) == 1,
1176 "IdxView must be a rank-1 Kokkos::View.");
1177 static_assert(static_cast<int>(ColView::rank) == 1,
1178 "ColView must be a rank-1 Kokkos::View.");
1181 using execution_space =
typename ExecutionSpace::execution_space;
1182 using size_type =
typename execution_space::size_type;
1193 UnpackArrayMultiColumnVariableStride(
const ExecutionSpace& ,
1194 const DstView& dst_,
1195 const SrcView& src_,
1196 const IdxView& idx_,
1197 const ColView& col_,
1199 const size_t numCols_)
1205 , numCols(numCols_) {}
1207 template <
class TagType>
1208 KOKKOS_INLINE_FUNCTION
void
1209 operator()(TagType tag,
const size_type k)
const {
1210 static_assert(std::is_same<TagType, atomic_tag>::value ||
1211 std::is_same<TagType, nonatomic_tag>::value,
1212 "TagType must be atomic_tag or nonatomic_tag.");
1214 const typename IdxView::value_type localRow = idx(k);
1215 const size_t offset = k * numCols;
1216 for (
size_t j = 0; j < numCols; ++j) {
1217 op(tag, dst(localRow, col(j)), src(offset + j));
1222 unpack(
const ExecutionSpace& execSpace,
1228 const size_t numCols,
1229 const bool use_atomic_updates) {
1230 if (use_atomic_updates) {
1232 Kokkos::RangePolicy<atomic_tag, execution_space, size_type>;
1233 Kokkos::parallel_for(
"Tpetra::MultiVector unpack var stride atomic",
1234 range_type(0, idx.size()),
1235 UnpackArrayMultiColumnVariableStride(execSpace, dst, src,
1236 idx, col, op, numCols));
1239 Kokkos::RangePolicy<nonatomic_tag, execution_space, size_type>;
1240 Kokkos::parallel_for(
"Tpetra::MultiVector unpack var stride nonatomic",
1241 range_type(0, idx.size()),
1242 UnpackArrayMultiColumnVariableStride(execSpace, dst, src,
1243 idx, col, op, numCols));
1248 template <
typename ExecutionSpace,
1254 typename SizeType =
typename ExecutionSpace::execution_space::size_type,
1255 typename Enabled =
void>
1256 class UnpackArrayMultiColumnVariableStrideWithBoundsCheck {
1258 static_assert(Kokkos::is_view<DstView>::value,
1259 "DstView must be a Kokkos::View.");
1260 static_assert(Kokkos::is_view<SrcView>::value,
1261 "SrcView must be a Kokkos::View.");
1262 static_assert(Kokkos::is_view<IdxView>::value,
1263 "IdxView must be a Kokkos::View.");
1264 static_assert(Kokkos::is_view<ColView>::value,
1265 "ColView must be a Kokkos::View.");
1266 static_assert(static_cast<int>(DstView::rank) == 2,
1267 "DstView must be a rank-2 Kokkos::View.");
1268 static_assert(static_cast<int>(SrcView::rank) == 1,
1269 "SrcView must be a rank-1 Kokkos::View.");
1270 static_assert(static_cast<int>(IdxView::rank) == 1,
1271 "IdxView must be a rank-1 Kokkos::View.");
1272 static_assert(static_cast<int>(ColView::rank) == 1,
1273 "ColView must be a rank-1 Kokkos::View.");
1274 static_assert(std::is_integral<SizeType>::value,
1275 "SizeType must be a built-in integer type.");
1278 using execution_space =
typename ExecutionSpace::execution_space;
1279 using size_type = SizeType;
1280 using value_type = size_t;
1291 UnpackArrayMultiColumnVariableStrideWithBoundsCheck(
const ExecutionSpace& ,
1292 const DstView& dst_,
1293 const SrcView& src_,
1294 const IdxView& idx_,
1295 const ColView& col_,
1297 const size_t numCols_)
1303 , numCols(numCols_) {}
1305 template <
class TagType>
1306 KOKKOS_INLINE_FUNCTION
void
1307 operator()(TagType tag,
1309 value_type& lclErrorCount)
const {
1310 static_assert(std::is_same<TagType, atomic_tag>::value ||
1311 std::is_same<TagType, nonatomic_tag>::value,
1312 "TagType must be atomic_tag or nonatomic_tag.");
1313 using row_index_type =
typename IdxView::non_const_value_type;
1314 using col_index_type =
typename ColView::non_const_value_type;
1316 const row_index_type lclRow = idx(k);
1317 if (lclRow < static_cast<row_index_type>(0) ||
1318 lclRow >= static_cast<row_index_type>(dst.extent(0))) {
1321 const size_type offset = k * numCols;
1322 for (size_type j = 0; j < numCols; ++j) {
1323 const col_index_type lclCol = col(j);
1324 if (Impl::outOfBounds<col_index_type>(lclCol, dst.extent(1))) {
1327 op(tag, dst(lclRow, col(j)), src(offset + j));
1333 KOKKOS_INLINE_FUNCTION
void
1334 init(value_type& initialErrorCount)
const {
1335 initialErrorCount = 0;
1338 KOKKOS_INLINE_FUNCTION
void
1339 join(value_type& dstErrorCount,
1340 const value_type& srcErrorCount)
const {
1341 dstErrorCount += srcErrorCount;
1345 unpack(
const ExecutionSpace& execSpace,
1351 const size_type numCols,
1352 const bool use_atomic_updates) {
1353 using row_index_type =
typename IdxView::non_const_value_type;
1354 using col_index_type =
typename ColView::non_const_value_type;
1356 size_t errorCount = 0;
1357 if (use_atomic_updates) {
1359 Kokkos::RangePolicy<atomic_tag, execution_space, size_type>;
1360 Kokkos::parallel_reduce(
"Tpetra::MultiVector unpack var stride atomic debug only",
1361 range_type(0, idx.size()),
1362 UnpackArrayMultiColumnVariableStrideWithBoundsCheck(execSpace, dst, src, idx, col, op, numCols),
1366 Kokkos::RangePolicy<nonatomic_tag, execution_space, size_type>;
1367 Kokkos::parallel_reduce(
"Tpetra::MultiVector unpack var stride nonatomic debug only",
1368 range_type(0, idx.size()),
1369 UnpackArrayMultiColumnVariableStrideWithBoundsCheck(execSpace, dst, src, idx, col, op, numCols),
1373 if (errorCount != 0) {
1374 constexpr
size_t maxNumBadIndicesToPrint = 100;
1376 std::ostringstream os;
1377 os <<
"Tpetra::MultiVector multicolumn variable stride unpack kernel "
1380 <<
" error" << (errorCount != size_t(1) ?
"s" :
"") <<
". ";
1386 auto idx_h = Kokkos::create_mirror_view(idx);
1391 std::vector<row_index_type> badRows;
1392 const size_type numRowInds = idx_h.extent(0);
1393 for (size_type k = 0; k < numRowInds; ++k) {
1394 if (idx_h(k) < static_cast<row_index_type>(0) ||
1395 idx_h(k) >= static_cast<row_index_type>(dst.extent(0))) {
1396 badRows.push_back(idx_h(k));
1400 if (badRows.size() != 0) {
1401 os << badRows.size() <<
" out-of-bounds row ind"
1402 << (badRows.size() != size_t(1) ?
"ices" :
"ex");
1403 if (badRows.size() <= maxNumBadIndicesToPrint) {
1405 for (
size_t k = 0; k < badRows.size(); ++k) {
1407 if (k + 1 < badRows.size()) {
1416 os <<
"No out-of-bounds row indices. ";
1421 auto col_h = Kokkos::create_mirror_view(col);
1426 std::vector<col_index_type> badCols;
1427 const size_type numColInds = col_h.extent(0);
1428 for (size_type k = 0; k < numColInds; ++k) {
1429 if (Impl::outOfBounds<col_index_type>(col_h(k), dst.extent(1))) {
1430 badCols.push_back(col_h(k));
1434 if (badCols.size() != 0) {
1435 os << badCols.size() <<
" out-of-bounds column ind"
1436 << (badCols.size() != size_t(1) ?
"ices" :
"ex");
1437 if (badCols.size() <= maxNumBadIndicesToPrint) {
1438 for (
size_t k = 0; k < badCols.size(); ++k) {
1441 if (k + 1 < badCols.size()) {
1450 os <<
"No out-of-bounds column indices. ";
1453 TEUCHOS_TEST_FOR_EXCEPTION(errorCount != 0 && badRows.size() == 0 && badCols.size() == 0,
1455 "Tpetra::MultiVector variable stride unpack "
1456 "kernel reports errorCount="
1457 << errorCount <<
", but we failed "
1458 "to find any bad rows or columns. This should never happen. "
1459 "Please report this to the Tpetra developers.");
1461 throw std::runtime_error(os.str());
1466 template <
typename ExecutionSpace,
1472 void unpack_array_multi_column_variable_stride(
const ExecutionSpace& execSpace,
1478 const size_t numCols,
1479 const bool use_atomic_updates,
1481 static_assert(Kokkos::is_view<DstView>::value,
1482 "DstView must be a Kokkos::View.");
1483 static_assert(Kokkos::is_view<SrcView>::value,
1484 "SrcView must be a Kokkos::View.");
1485 static_assert(Kokkos::is_view<IdxView>::value,
1486 "IdxView must be a Kokkos::View.");
1487 static_assert(Kokkos::is_view<ColView>::value,
1488 "ColView must be a Kokkos::View.");
1489 static_assert(static_cast<int>(DstView::rank) == 2,
1490 "DstView must be a rank-2 Kokkos::View.");
1491 static_assert(static_cast<int>(SrcView::rank) == 1,
1492 "SrcView must be a rank-1 Kokkos::View.");
1493 static_assert(static_cast<int>(IdxView::rank) == 1,
1494 "IdxView must be a rank-1 Kokkos::View.");
1495 static_assert(static_cast<int>(ColView::rank) == 1,
1496 "ColView must be a rank-1 Kokkos::View.");
1500 UnpackArrayMultiColumnVariableStrideWithBoundsCheck<ExecutionSpace,
1501 DstView, SrcView, IdxView, ColView, Op>;
1502 impl_type::unpack(execSpace, dst, src, idx, col, op, numCols,
1503 use_atomic_updates);
1505 using impl_type = UnpackArrayMultiColumnVariableStride<ExecutionSpace,
1506 DstView, SrcView, IdxView, ColView, Op>;
1507 impl_type::unpack(execSpace, dst, src, idx, col, op, numCols,
1508 use_atomic_updates);
1512 template <
typename DstView,
typename SrcView,
1513 typename DstIdxView,
typename SrcIdxView,
typename Op,
1514 typename Enabled =
void>
1515 struct PermuteArrayMultiColumn {
1516 using size_type =
typename DstView::size_type;
1525 PermuteArrayMultiColumn(
const DstView& dst_,
1526 const SrcView& src_,
1527 const DstIdxView& dst_idx_,
1528 const SrcIdxView& src_idx_,
1529 const size_t numCols_,
1538 KOKKOS_INLINE_FUNCTION
void
1539 operator()(
const size_type k)
const {
1540 const typename DstIdxView::value_type toRow = dst_idx(k);
1541 const typename SrcIdxView::value_type fromRow = src_idx(k);
1543 for (
size_t j = 0; j < numCols; ++j) {
1544 op(tag, dst(toRow, j), src(fromRow, j));
1548 template <
typename ExecutionSpace>
1550 permute(
const ExecutionSpace& space,
1553 const DstIdxView& dst_idx,
1554 const SrcIdxView& src_idx,
1555 const size_t numCols,
1558 Kokkos::RangePolicy<ExecutionSpace, size_type>;
1560 const size_type n = std::min(dst_idx.size(), src_idx.size());
1561 Kokkos::parallel_for(
"Tpetra::MultiVector permute multicol const stride",
1562 range_type(space, 0, n),
1563 PermuteArrayMultiColumn(dst, src, dst_idx, src_idx, numCols, op));
1569 template <
typename ExecutionSpace,
typename DstView,
typename SrcView,
1570 typename DstIdxView,
typename SrcIdxView,
typename Op>
1571 void permute_array_multi_column(
const ExecutionSpace& space,
const DstView& dst,
1572 const SrcView& src,
const DstIdxView& dst_idx,
1573 const SrcIdxView& src_idx,
size_t numCols,
1575 PermuteArrayMultiColumn<DstView, SrcView, DstIdxView, SrcIdxView,
1576 Op>::permute(space, dst, src, dst_idx, src_idx,
1582 template <
typename DstView,
typename SrcView,
1583 typename DstIdxView,
typename SrcIdxView,
typename Op>
1584 void permute_array_multi_column(
const DstView& dst,
1586 const DstIdxView& dst_idx,
1587 const SrcIdxView& src_idx,
1590 using execution_space =
typename DstView::execution_space;
1591 PermuteArrayMultiColumn<DstView, SrcView, DstIdxView, SrcIdxView, Op>::permute(
1592 execution_space(), dst, src, dst_idx, src_idx, numCols, op);
1595 template <
typename DstView,
typename SrcView,
1596 typename DstIdxView,
typename SrcIdxView,
1597 typename DstColView,
typename SrcColView,
typename Op,
1598 typename Enabled =
void>
1599 struct PermuteArrayMultiColumnVariableStride {
1600 using size_type =
typename DstView::size_type;
1611 PermuteArrayMultiColumnVariableStride(
const DstView& dst_,
1612 const SrcView& src_,
1613 const DstIdxView& dst_idx_,
1614 const SrcIdxView& src_idx_,
1615 const DstColView& dst_col_,
1616 const SrcColView& src_col_,
1617 const size_t numCols_,
1628 KOKKOS_INLINE_FUNCTION
void
1629 operator()(
const size_type k)
const {
1630 const typename DstIdxView::value_type toRow = dst_idx(k);
1631 const typename SrcIdxView::value_type fromRow = src_idx(k);
1632 const nonatomic_tag tag;
1633 for (
size_t j = 0; j < numCols; ++j) {
1634 op(tag, dst(toRow, dst_col(j)), src(fromRow, src_col(j)));
1638 template <
typename ExecutionSpace>
1640 permute(
const ExecutionSpace& space,
1643 const DstIdxView& dst_idx,
1644 const SrcIdxView& src_idx,
1645 const DstColView& dst_col,
1646 const SrcColView& src_col,
1647 const size_t numCols,
1649 static_assert(Kokkos::SpaceAccessibility<
1650 ExecutionSpace,
typename DstView::memory_space>::accessible,
1651 "ExecutionSpace must be able to access DstView");
1653 using range_type = Kokkos::RangePolicy<ExecutionSpace, size_type>;
1654 const size_type n = std::min(dst_idx.size(), src_idx.size());
1655 Kokkos::parallel_for(
"Tpetra::MultiVector permute multicol var stride",
1656 range_type(space, 0, n),
1657 PermuteArrayMultiColumnVariableStride(dst, src, dst_idx, src_idx,
1658 dst_col, src_col, numCols, op));
1664 template <
typename ExecutionSpace,
typename DstView,
typename SrcView,
1665 typename DstIdxView,
typename SrcIdxView,
typename DstColView,
1666 typename SrcColView,
typename Op>
1667 void permute_array_multi_column_variable_stride(
1668 const ExecutionSpace& space,
const DstView& dst,
const SrcView& src,
1669 const DstIdxView& dst_idx,
const SrcIdxView& src_idx,
1670 const DstColView& dst_col,
const SrcColView& src_col,
size_t numCols,
1672 PermuteArrayMultiColumnVariableStride<DstView, SrcView, DstIdxView,
1673 SrcIdxView, DstColView, SrcColView,
1674 Op>::permute(space, dst, src, dst_idx,
1675 src_idx, dst_col, src_col,
1681 template <
typename DstView,
typename SrcView,
1682 typename DstIdxView,
typename SrcIdxView,
1683 typename DstColView,
typename SrcColView,
typename Op>
1684 void permute_array_multi_column_variable_stride(
const DstView& dst,
1686 const DstIdxView& dst_idx,
1687 const SrcIdxView& src_idx,
1688 const DstColView& dst_col,
1689 const SrcColView& src_col,
1692 using execution_space =
typename DstView::execution_space;
1693 PermuteArrayMultiColumnVariableStride<DstView, SrcView,
1694 DstIdxView, SrcIdxView, DstColView, SrcColView, Op>::permute(execution_space(), dst, src, dst_idx, src_idx, dst_col, src_col, numCols, op);
1701 #endif // TPETRA_KOKKOS_REFACTOR_DETAILS_MULTI_VECTOR_DIST_OBJECT_KERNELS_HPP
KOKKOS_INLINE_FUNCTION bool outOfBounds(const IntegerType x, const IntegerType exclusiveUpperBound)
Is x out of bounds? That is, is x less than zero, or greater than or equal to the given exclusive upp...
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.
Is x out of bounds? That is, is x less than zero, or greater than or equal to the given exclusive upp...