10 #ifndef TPETRA_UTIL_HPP
11 #define TPETRA_UTIL_HPP
22 #include "Tpetra_ConfigDefs.hpp"
23 #include "Kokkos_DualView.hpp"
24 #include "KokkosCompat_View.hpp"
25 #include "Teuchos_Assert.hpp"
26 #include "Teuchos_CommHelpers.hpp"
27 #include "Teuchos_OrdinalTraits.hpp"
28 #include "Teuchos_TypeNameTraits.hpp"
29 #include "Teuchos_Utils.hpp"
37 #if defined(HAVE_TPETRA_PRINT_EFFICIENCY_WARNINGS)
38 #define TPETRA_EFFICIENCY_WARNING(throw_exception_test, msg) \
64 const bool tpetraEfficiencyWarningTest = (throw_exception_test); \
65 if (tpetraEfficiencyWarningTest) { \
66 std::ostringstream errStream; \
67 errStream << Teuchos::typeName(*this) << ":" << std::endl; \
68 errStream << "Efficiency warning: " << #throw_exception_test << std::endl; \
70 std::string err = errStream.str(); \
71 if (TPETRA_PRINTS_EFFICIENCY_WARNINGS && tpetraEfficiencyWarningTest) { \
72 std::cerr << err << std::endl; \
77 #define TPETRA_EFFICIENCY_WARNING(throw_exception_test, msg)
105 #if defined(HAVE_TPETRA_THROW_ABUSE_WARNINGS) || defined(HAVE_TPETRA_PRINT_ABUSE_WARNINGS)
106 #define TPETRA_ABUSE_WARNING(throw_exception_test, Exception, msg) \
109 std::ostringstream errStream; \
110 errStream << Teuchos::typeName(*this) << msg; \
111 std::string err = errStream.str(); \
112 if (TPETRA_PRINTS_ABUSE_WARNINGS && (throw_exception_test)) { \
113 std::cerr << err << std::endl; \
115 TEUCHOS_TEST_FOR_EXCEPTION(TPETRA_THROWS_ABUSE_WARNINGS && (throw_exception_test), Exception, err); \
118 #define TPETRA_ABUSE_WARNING(throw_exception_test, Exception, msg)
151 #define SHARED_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg, comm) \
153 using Teuchos::outArg; \
154 const int lcl_throw_exception = (throw_exception_test) ? Teuchos::rank(comm) + 1 : 0; \
156 Teuchos::reduceAll(comm, Teuchos::REDUCE_MAX, lcl_throw_exception, outArg(gbl_throw)); \
157 TEUCHOS_TEST_FOR_EXCEPTION(gbl_throw, Exception, \
158 msg << " Failure on at least one process, including process " << gbl_throw - 1 << "." << std::endl); \
174 template <
typename MapType,
typename KeyArgType,
typename ValueArgType>
177 const ValueArgType& v) {
178 typename MapType::iterator lb = m.lower_bound(k);
179 if (lb != m.end() && !(m.key_comp()(k, lb->first))) {
183 typedef typename MapType::value_type MVT;
184 return (m.insert(lb, MVT(k, v)));
195 namespace SortDetails {
206 bool isAlreadySorted(
const IT1& first,
const IT1& last) {
207 typedef typename std::iterator_traits<IT1>::difference_type DT;
208 DT myit = Teuchos::OrdinalTraits<DT>::one();
209 const DT sz = last - first;
210 for (; myit < sz; ++myit) {
211 if (first[myit] < first[myit - 1]) {
228 IT getPivot(
const IT& first,
const IT& last) {
229 IT pivot(first + (last - first) / 2);
230 if (*first <= *pivot && *(last - 1) <= *first)
232 else if (*(last - 1) <= *pivot && *first <= *(last - 1))
251 template <
class IT1,
class IT2>
258 typename std::iterator_traits<IT1>::value_type piv(*pivot);
259 std::swap(*pivot, *(last1 - 1));
260 std::swap(first2[(pivot - first1)], *(last2 - 1));
262 for (IT1 it = first1; it != last1 - 1; ++it) {
264 std::swap(*store1, *it);
265 std::swap(first2[(store1 - first1)], first2[(it - first1)]);
269 std::swap(*(last1 - 1), *store1);
270 std::swap(*(last2 - 1), first2[store1 - first1]);
290 template <
class IT1,
class IT2,
class IT3>
299 typename std::iterator_traits<IT1>::value_type piv(*pivot);
300 std::swap(*pivot, *(last1 - 1));
301 std::swap(first2[(pivot - first1)], *(last2 - 1));
302 std::swap(first3[(pivot - first1)], *(last3 - 1));
304 for (IT1 it = first1; it != last1 - 1; ++it) {
306 std::swap(*store1, *it);
307 std::swap(first2[(store1 - first1)], first2[(it - first1)]);
308 std::swap(first3[(store1 - first1)], first3[(it - first1)]);
312 std::swap(*(last1 - 1), *store1);
313 std::swap(*(last2 - 1), first2[store1 - first1]);
314 std::swap(*(last3 - 1), first3[store1 - first1]);
328 template <
class IT1,
class IT2>
334 typedef typename std::iterator_traits<IT1>::difference_type DT;
335 DT DT1 = Teuchos::OrdinalTraits<DT>::one();
336 if (last1 - first1 > DT1) {
337 IT1 pivot = getPivot(first1, last1);
338 pivot = partition2(first1, last1, first2, last2, pivot);
339 quicksort2(first1, pivot, first2, first2 + (pivot - first1));
340 quicksort2(pivot + 1, last1, first2 + (pivot - first1) + 1, last2);
356 template <
class IT1,
class IT2,
class IT3>
364 typedef typename std::iterator_traits<IT1>::difference_type DT;
365 DT DT1 = Teuchos::OrdinalTraits<DT>::one();
366 if (last1 - first1 > DT1) {
367 IT1 pivot = getPivot(first1, last1);
368 pivot = partition3(first1, last1, first2, last2, first3, last3, pivot);
369 quicksort3(first1, pivot, first2, first2 + (pivot - first1), first3, first3 + (pivot - first1));
370 quicksort3(pivot + 1, last1, first2 + (pivot - first1) + 1, last2, first3 + (pivot - first1) + 1, last3);
380 template <
class IT1,
class IT2,
class IT3>
388 typedef typename std::iterator_traits<IT1>::difference_type DT;
389 DT n = last1 - first1;
391 DT z = Teuchos::OrdinalTraits<DT>::zero();
394 for (DT j = 0; j < max; j++) {
395 for (DT k = j; k >= 0; k -= m) {
396 if (first1[k + m] >= first1[k])
398 std::swap(first1[k + m], first1[k]);
399 std::swap(first2[k + m], first2[k]);
400 std::swap(first3[k + m], first3[k]);
413 template <
class IT1,
class IT2>
419 typedef typename std::iterator_traits<IT1>::difference_type DT;
420 DT n = last1 - first1;
422 DT z = Teuchos::OrdinalTraits<DT>::zero();
425 for (DT j = 0; j < max; j++) {
426 for (DT k = j; k >= 0; k -= m) {
427 if (first1[k + m] >= first1[k])
429 std::swap(first1[k + m], first1[k]);
430 std::swap(first2[k + m], first2[k]);
441 template <
typename IT1>
442 std::vector<typename std::iterator_traits<IT1>::difference_type> sort_indexes(IT1 first, IT1 last) {
443 typedef typename std::iterator_traits<IT1>::difference_type DT;
445 DT length = last - first;
446 std::vector<DT> idx(length);
447 std::iota(idx.begin(), idx.end(), 0);
449 std::stable_sort(idx.begin(), idx.end(),
450 [&first](
size_t i1,
size_t i2) {
return first[i1] < first[i2]; });
458 template <
typename IT1,
typename IT2>
459 void apply_permutation(
463 typedef typename std::iterator_traits<IT1>::difference_type DT;
464 typedef typename std::iterator_traits<IT1>::value_type T;
468 Kokkos::View<T*, Kokkos::HostSpace> tmp(Kokkos::view_alloc(Kokkos::WithoutInitializing,
"tmp"), n);
470 Kokkos::parallel_for(
"apply_permutation_1",
471 Kokkos::RangePolicy<Kokkos::DefaultHostExecutionSpace>(0, n),
473 tmp(j) = first[indices[j]];
475 Kokkos::parallel_for(
"apply_permutation_2",
476 Kokkos::RangePolicy<Kokkos::DefaultHostExecutionSpace>(0, n),
488 template <
class IT1,
class IT2>
489 void std_sort2(
const IT1& first1,
493 auto indices = sort_indexes(first1, last1);
494 apply_permutation(first1, last1, indices);
495 apply_permutation(first2, last2, indices);
504 template <
class IT1,
class IT2,
class IT3>
512 auto indices = sort_indexes(first1, last1);
513 apply_permutation(first1, last1, indices);
514 apply_permutation(first2, last2, indices);
515 apply_permutation(first3, last3, indices);
538 template <
class IT1,
class IT2>
539 void sort2(
const IT1& first1,
const IT1& last1,
const IT2& first2,
const bool stableSort =
false) {
544 if (SortDetails::isAlreadySorted(first1, last1)) {
548 SortDetails::std_sort2(first1, last1, first2, first2 + (last1 - first1));
550 SortDetails::sh_sort2(first1, last1, first2, first2 + (last1 - first1));
551 #ifdef HAVE_TPETRA_DEBUG
552 if (!SortDetails::isAlreadySorted(first1, last1)) {
553 std::cout <<
"Trouble: sort() did not sort !!" << std::endl;
575 template <
class View1,
class View2>
576 void sort2(View1& view1,
const size_t& size, View2& view2) {
580 Teuchos::ArrayRCP<typename View1::non_const_value_type> view1_rcp = Kokkos::Compat::persistingView(view1, 0, size);
581 Teuchos::ArrayRCP<typename View2::non_const_value_type> view2_rcp = Kokkos::Compat::persistingView(view2, 0, size);
583 sort2(view1_rcp.begin(), view1_rcp.end(), view2_rcp.begin());
594 template <
class View>
595 void sort(View& view,
const size_t& size) {
599 Teuchos::ArrayRCP<typename View::non_const_value_type> view_rcp = Kokkos::Compat::persistingView(view, 0, size);
601 std::sort(view_rcp.begin(), view_rcp.end());
612 template <
class View>
616 Teuchos::ArrayRCP<typename View::non_const_value_type> view_rcp = Kokkos::Compat::persistingView(view, 0, size);
618 std::sort(view_rcp.rbegin(), view_rcp.rend());
636 template <
class IT1,
class IT2,
class IT3>
637 void sort3(
const IT1& first1,
const IT1& last1,
const IT2& first2,
638 const IT3& first3,
const bool stableSort =
false) {
643 if (SortDetails::isAlreadySorted(first1, last1)) {
647 SortDetails::std_sort3(first1, last1, first2, first2 + (last1 - first1), first3,
648 first3 + (last1 - first1));
650 SortDetails::sh_sort3(first1, last1, first2, first2 + (last1 - first1), first3,
651 first3 + (last1 - first1));
652 #ifdef HAVE_TPETRA_DEBUG
653 if (!SortDetails::isAlreadySorted(first1, last1)) {
654 std::cout <<
" Trouble sort did not actually sort... !!!!!!" << std::endl;
703 template <
class IT1,
class IT2>
704 void merge2(IT1& indResultOut, IT2& valResultOut,
705 IT1 indBeg, IT1 indEnd,
707 if (indBeg == indEnd) {
708 indResultOut = indBeg;
709 valResultOut = valBeg;
711 IT1 indResult = indBeg;
712 IT2 valResult = valBeg;
713 if (indBeg != indEnd) {
716 while (indBeg != indEnd) {
717 if (*indResult == *indBeg) {
718 *valResult += *valBeg;
720 *(++indResult) = *indBeg;
721 *(++valResult) = *valBeg;
736 indResultOut = indResult;
737 valResultOut = valResult;
789 template <
class IT1,
class IT2,
class BinaryFunction>
790 void merge2(IT1& indResultOut, IT2& valResultOut,
791 IT1 indBeg, IT1 indEnd,
792 IT2 valBeg, IT2 valEnd,
794 if (indBeg == indEnd) {
795 indResultOut = indBeg;
796 valResultOut = valBeg;
798 IT1 indResult = indBeg;
799 IT2 valResult = valBeg;
800 if (indBeg != indEnd) {
803 while (indBeg != indEnd) {
804 if (*indResult == *indBeg) {
805 *valResult = f(*valResult, *valBeg);
807 *(++indResult) = *indBeg;
808 *(++valResult) = *valBeg;
818 indResultOut = indResult;
819 valResultOut = valResult;
851 template <
class KeyInputIterType,
class ValueInputIterType,
852 class KeyOutputIterType,
class ValueOutputIterType,
853 class BinaryFunction>
855 ValueInputIterType valBeg1, ValueInputIterType valEnd1,
856 KeyInputIterType keyBeg2, KeyInputIterType keyEnd2,
857 ValueInputIterType valBeg2, ValueInputIterType valEnd2,
858 KeyOutputIterType keyOut, ValueOutputIterType valOut,
860 while (keyBeg1 != keyEnd1 && keyBeg2 != keyEnd2) {
861 if (*keyBeg1 < *keyBeg2) {
862 *keyOut++ = *keyBeg1++;
863 *valOut++ = *valBeg1++;
864 }
else if (*keyBeg1 > *keyBeg2) {
865 *keyOut++ = *keyBeg2++;
866 *valOut++ = *valBeg2++;
868 *keyOut++ = *keyBeg1;
869 *valOut++ = f(*valBeg1, *valBeg2);
877 std::copy(keyBeg1, keyEnd1, keyOut);
878 std::copy(valBeg1, valEnd1, valOut);
879 std::copy(keyBeg2, keyEnd2, keyOut);
880 std::copy(valBeg2, valEnd2, valOut);
883 template <
class KeyInputIterType>
885 keyMergeCount(KeyInputIterType keyBeg1, KeyInputIterType keyEnd1,
886 KeyInputIterType keyBeg2, KeyInputIterType keyEnd2) {
888 while (keyBeg1 != keyEnd1 && keyBeg2 != keyEnd2) {
889 if (*keyBeg1 < *keyBeg2) {
891 }
else if (*keyBeg1 > *keyBeg2) {
900 count +=
static_cast<size_t>(keyEnd1 - keyBeg1) +
901 static_cast<size_t>(keyEnd2 - keyBeg2);
925 bool congruent(
const Teuchos::Comm<int>& comm1,
926 const Teuchos::Comm<int>& comm2);
937 template <
class DualViewType>
938 Teuchos::ArrayView<typename DualViewType::t_dev::value_type>
940 static_assert(static_cast<int>(DualViewType::t_dev::rank) == 1,
941 "The input DualView must have rank 1.");
942 TEUCHOS_TEST_FOR_EXCEPTION(x.need_sync_host(), std::logic_error,
944 "input Kokkos::DualView was most recently modified on device, but this "
945 "function needs the host view of the data to be the most recently "
948 auto x_host = x.view_host();
949 typedef typename DualViewType::t_dev::value_type value_type;
953 const auto len = x_host.extent(0);
954 return Teuchos::ArrayView<value_type>(len != 0 ? x_host.data() :
nullptr,
974 template <
class T,
class DT>
975 Kokkos::DualView<T*, DT>
978 const bool leaveOnHost) {
979 using Kokkos::MemoryUnmanaged;
980 typedef typename DT::memory_space DMS;
981 typedef typename DT::execution_space execution_space;
982 typedef Kokkos::HostSpace HMS;
984 const size_t len =
static_cast<size_t>(x_av.size());
985 Kokkos::View<const T*, HMS, MemoryUnmanaged> x_in(x_av.getRawPtr(), len);
986 Kokkos::DualView<T*, DT> x_out(label, len);
992 x_out.template modify<DMS>();
1006 template <
class DualViewType>
1008 const auto host = dv.need_sync_device();
1009 const auto dev = dv.need_sync_host();
1011 std::ostringstream os;
1012 os << name <<
": {size: " << dv.extent(0)
1013 <<
", sync: {host: " << host <<
", dev: " << dev <<
"}";
1021 template <
class ArrayType>
1025 const size_t maxNumToPrint) {
1026 out << name <<
": [";
1028 const size_t numEnt(x.size());
1029 if (maxNumToPrint == 0) {
1034 const size_t numToPrint = numEnt > maxNumToPrint ? maxNumToPrint : numEnt;
1036 for (; k < numToPrint; ++k) {
1038 if (k +
size_t(1) < numToPrint) {
1052 std::unique_ptr<std::string>
1054 const char prefix[]);
1063 std::unique_ptr<std::string>
1065 const char functionName[]);
1073 std::unique_ptr<std::string>
1075 const char className[],
1076 const char methodName[]);
1081 #endif // TPETRA_UTIL_HPP
bool congruent(const Teuchos::Comm< int > &comm1, const Teuchos::Comm< int > &comm2)
Whether the two communicators are congruent.
void merge2(IT1 &indResultOut, IT2 &valResultOut, IT1 indBeg, IT1 indEnd, IT2 valBeg, IT2)
Merge values in place, additively, with the same index.
void sort3(const IT1 &first1, const IT1 &last1, const IT2 &first2, const IT3 &first3, const bool stableSort=false)
Sort the first array, and apply the same permutation to the second and third arrays.
void verbosePrintArray(std::ostream &out, const ArrayType &x, const char name[], const size_t maxNumToPrint)
Print min(x.size(), maxNumToPrint) entries of x.
void sort(View &view, const size_t &size)
Convenience wrapper for std::sort for host-accessible views.
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.
Kokkos::DualView< T *, DT > getDualViewCopyFromArrayView(const Teuchos::ArrayView< const T > &x_av, const char label[], const bool leaveOnHost)
Get a 1-D Kokkos::DualView which is a deep copy of the input Teuchos::ArrayView (which views host mem...
void keyValueMerge(KeyInputIterType keyBeg1, KeyInputIterType keyEnd1, ValueInputIterType valBeg1, ValueInputIterType valEnd1, KeyInputIterType keyBeg2, KeyInputIterType keyEnd2, ValueInputIterType valBeg2, ValueInputIterType valEnd2, KeyOutputIterType keyOut, ValueOutputIterType valOut, BinaryFunction f)
Merge two sorted (by keys) sequences of unique (key,value) pairs by combining pairs with equal keys...
void sort2(const IT1 &first1, const IT1 &last1, const IT2 &first2, const bool stableSort=false)
Sort the first array, and apply the resulting permutation to the second array.
MapType::iterator efficientAddOrUpdate(MapType &m, const KeyArgType &k, const ValueArgType &v)
Efficiently insert or replace an entry in an std::map.
std::string dualViewStatusToString(const DualViewType &dv, const char name[])
Return the status of the given Kokkos::DualView, as a human-readable string.
Teuchos::ArrayView< typename DualViewType::t_dev::value_type > getArrayViewFromDualView(const DualViewType &x)
Get a Teuchos::ArrayView which views the host Kokkos::View of the input 1-D Kokkos::DualView.
void reverse_sort(View &view, const size_t &size)
Convenience wrapper for a reversed std::sort for host-accessible views.
std::unique_ptr< std::string > createPrefix(const int myRank, const char prefix[])
Create string prefix for each line of verbose output.