Ifpack2 Templated Preconditioning Package Version 1.0
Loading...
Searching...
No Matches
Ifpack2_BlockHelper.hpp
1// @HEADER
2// *****************************************************************************
3// Ifpack2: Templated Object-Oriented Algebraic Preconditioner Package
4//
5// Copyright 2009 NTESS and the Ifpack2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef IFPACK2_BLOCKHELPER_IMPL_HPP
11#define IFPACK2_BLOCKHELPER_IMPL_HPP
12
13#include "Ifpack2_BlockHelper_Timers.hpp"
14
15namespace Ifpack2 {
16
17namespace BlockHelperDetails {
18
19namespace KB = KokkosBatched;
20
24using do_not_initialize_tag = Kokkos::ViewAllocateWithoutInitializing;
25
26template <typename MemoryTraitsType, Kokkos::MemoryTraitsFlags flag>
27using MemoryTraits = Kokkos::MemoryTraits<MemoryTraitsType::is_unmanaged |
28 MemoryTraitsType::is_random_access |
29 flag>;
30
31template <typename ViewType>
32using Unmanaged = Kokkos::View<typename ViewType::data_type,
33 typename ViewType::array_layout,
34 typename ViewType::device_type,
35 MemoryTraits<typename ViewType::memory_traits, Kokkos::Unmanaged>>;
36template <typename ViewType>
37using Atomic = Kokkos::View<typename ViewType::data_type,
38 typename ViewType::array_layout,
39 typename ViewType::device_type,
40 MemoryTraits<typename ViewType::memory_traits, Kokkos::Atomic>>;
41template <typename ViewType>
42using Const = Kokkos::View<typename ViewType::const_data_type,
43 typename ViewType::array_layout,
44 typename ViewType::device_type,
45 typename ViewType::memory_traits>;
46template <typename ViewType>
47using ConstUnmanaged = Const<Unmanaged<ViewType>>;
48
49template <typename ViewType>
50using AtomicUnmanaged = Atomic<Unmanaged<ViewType>>;
51
52template <typename ViewType>
53using Unmanaged = Kokkos::View<typename ViewType::data_type,
54 typename ViewType::array_layout,
55 typename ViewType::device_type,
56 MemoryTraits<typename ViewType::memory_traits, Kokkos::Unmanaged>>;
57
58template <typename ViewType>
59using Scratch = Kokkos::View<typename ViewType::data_type,
60 typename ViewType::array_layout,
61 typename ViewType::execution_space::scratch_memory_space,
62 MemoryTraits<typename ViewType::memory_traits, Kokkos::Unmanaged>>;
63
64// Uint32IndexedView and Uint32IndexedConstView: if mdspan is available, these
65// are versions of unmanaged view with uint32_t as the index_type.
66// Otherwise, they are default unmanaged Views (with 64-bit indexing).
67//
68// mdspan was controlled by KOKKOS_ENABLE_IMPL_MDSPAN before 5.3,
69// but after 5.3 is always available.
70#if defined(KOKKOS_ENABLE_IMPL_MDSPAN) || (KOKKOS_VERSION >= 50299)
71template <class OrigExtents, class NewIndexType, class Seq>
72struct ReplaceExtentsIndexType;
73
74template <class OrigExtents, class NewIndexType, size_t... Is>
75struct ReplaceExtentsIndexType<OrigExtents, NewIndexType,
76 std::index_sequence<Is...>> {
77 using type = Kokkos::extents<NewIndexType, OrigExtents::static_extent(Is)...>;
78};
79
80template <class OrigExtents, class NewIndexType>
81using ReplaceExtentsIndexType_t = typename ReplaceExtentsIndexType<
82 OrigExtents, NewIndexType,
83 std::make_index_sequence<OrigExtents::rank()>>::type;
84
85template <class ViewT, class NewIndexType>
86using ViewWithIndexType_t = Kokkos::View<
87 typename ViewT::element_type,
88 ReplaceExtentsIndexType_t<typename ViewT::extents_type, NewIndexType>,
89 typename ViewT::layout_type,
90 typename ViewT::accessor_type>;
91
92template <typename ViewT>
93using Uint32IndexedView = ViewWithIndexType_t<Unmanaged<ViewT>, uint32_t>;
94template <typename ViewT>
95using Uint32IndexedConstView = ViewWithIndexType_t<ConstUnmanaged<ViewT>, uint32_t>;
96#else
97template <typename ViewT>
98using Uint32IndexedView = Unmanaged<ViewT>;
99template <typename ViewT>
100using Uint32IndexedConstView = ConstUnmanaged<ViewT>;
101#endif
102
106template <typename LayoutType>
108template <>
109struct TpetraLittleBlock<Kokkos::LayoutLeft> {
110 template <typename T>
111 KOKKOS_INLINE_FUNCTION static T getFlatIndex(const T i, const T j, const T blksize) { return i + j * blksize; }
112};
113template <>
114struct TpetraLittleBlock<Kokkos::LayoutRight> {
115 template <typename T>
116 KOKKOS_INLINE_FUNCTION static T getFlatIndex(const T i, const T j, const T blksize) { return i * blksize + j; }
117};
118
122template <typename T>
124 typedef T type;
125};
126#if defined(IFPACK2_BLOCKHELPER_USE_SMALL_SCALAR_FOR_BLOCKTRIDIAG)
127template <>
128struct BlockTridiagScalarType<double> {
129 typedef float type;
130};
131// template<> struct SmallScalarType<Kokkos::complex<double> > { typedef Kokkos::complex<float> type; };
132#endif
133
137template <typename T>
138struct is_cuda {
139 enum : bool { value = false };
140};
141#if defined(KOKKOS_ENABLE_CUDA)
142template <>
143struct is_cuda<Kokkos::Cuda> {
144 enum : bool { value = true };
145};
146#endif
147
151template <typename T>
152struct is_hip {
153 enum : bool { value = false };
154};
155#if defined(KOKKOS_ENABLE_HIP)
156template <>
157struct is_hip<Kokkos::HIP> {
158 enum : bool { value = true };
159};
160#endif
161
165template <typename T>
166struct is_sycl {
167 enum : bool { value = false };
168};
169#if defined(KOKKOS_ENABLE_SYCL)
170template <>
171struct is_sycl<Kokkos::SYCL> {
172 enum : bool { value = true };
173};
174#endif
175
176template <typename T>
177struct is_device {
178 enum : bool { value = is_cuda<T>::value || is_hip<T>::value || is_sycl<T>::value };
179};
180
184template <typename T>
186 static void createInstance(T &exec_instance) {
187 exec_instance = T();
188 }
189#if defined(KOKKOS_ENABLE_CUDA)
190 static void createInstance(const cudaStream_t &s, T &exec_instance) {
191 exec_instance = T();
192 }
193#endif
194};
195
196#if defined(KOKKOS_ENABLE_CUDA)
197template <>
198struct ExecutionSpaceFactory<Kokkos::Cuda> {
199 static void createInstance(Kokkos::Cuda &exec_instance) {
200 exec_instance = Kokkos::Cuda();
201 }
202 static void createInstance(const cudaStream_t &s, Kokkos::Cuda &exec_instance) {
203 exec_instance = Kokkos::Cuda(s);
204 }
205};
206#endif
207
208#if defined(KOKKOS_ENABLE_HIP)
209template <>
210struct ExecutionSpaceFactory<Kokkos::HIP> {
211 static void createInstance(Kokkos::HIP &exec_instance) {
212 exec_instance = Kokkos::HIP();
213 }
214};
215#endif
216
217#if defined(KOKKOS_ENABLE_SYCL)
218template <>
219struct ExecutionSpaceFactory<Kokkos::SYCL> {
220 static void createInstance(Kokkos::SYCL &exec_instance) {
221 exec_instance = Kokkos::SYCL();
222 }
223};
224#endif
225
226#if defined(KOKKOS_ENABLE_CUDA) && defined(IFPACK2_BLOCKHELPER_ENABLE_PROFILE)
227#define IFPACK2_BLOCKHELPER_PROFILER_REGION_BEGIN \
228 cudaProfilerStart();
229
230#define IFPACK2_BLOCKHELPER_PROFILER_REGION_END \
231 { cudaProfilerStop(); }
232#else
234#define IFPACK2_BLOCKHELPER_PROFILER_REGION_BEGIN
235#define IFPACK2_BLOCKHELPER_PROFILER_REGION_END
236#endif
237
241template <typename CommPtrType>
242std::string get_msg_prefix(const CommPtrType &comm) {
243 const auto rank = comm->getRank();
244 const auto nranks = comm->getSize();
245 std::stringstream ss;
246 ss << "Rank " << rank << " of " << nranks << ": ";
247 return ss.str();
248}
249
253template <typename T, int N>
254struct ArrayValueType {
255 T v[N];
256 KOKKOS_INLINE_FUNCTION
257 ArrayValueType() {
258 for (int i = 0; i < N; ++i)
259 this->v[i] = 0;
260 }
261 KOKKOS_INLINE_FUNCTION
262 ArrayValueType(const ArrayValueType &b) {
263 for (int i = 0; i < N; ++i)
264 this->v[i] = b.v[i];
265 }
266};
267template <typename T, int N>
268static KOKKOS_INLINE_FUNCTION void
269operator+=(ArrayValueType<T, N> &a,
270 const ArrayValueType<T, N> &b) {
271 for (int i = 0; i < N; ++i)
272 a.v[i] += b.v[i];
273}
274
278template <typename T, int N, typename ExecSpace>
279struct SumReducer {
280 typedef SumReducer reducer;
281 typedef ArrayValueType<T, N> value_type;
282 typedef Kokkos::View<value_type, ExecSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>> result_view_type;
283 value_type *value;
284
285 KOKKOS_INLINE_FUNCTION
286 SumReducer(value_type &val)
287 : value(&val) {}
288
289 KOKKOS_INLINE_FUNCTION
290 void join(value_type &dst, value_type const &src) const {
291 for (int i = 0; i < N; ++i)
292 dst.v[i] += src.v[i];
293 }
294 KOKKOS_INLINE_FUNCTION
295 void init(value_type &val) const {
296 for (int i = 0; i < N; ++i)
297 val.v[i] = 0;
298 }
299 KOKKOS_INLINE_FUNCTION
300 value_type &reference() {
301 return *value;
302 }
303 KOKKOS_INLINE_FUNCTION
304 result_view_type view() const {
305 return result_view_type(value);
306 }
307};
308
312template <typename MatrixType>
313struct ImplType {
317 typedef size_t size_type;
318 typedef MatrixType matrix_type;
319 typedef typename MatrixType::scalar_type scalar_type;
320 typedef typename MatrixType::local_ordinal_type local_ordinal_type;
321 typedef typename MatrixType::global_ordinal_type global_ordinal_type;
322 typedef typename MatrixType::node_type node_type;
323
327 typedef typename KokkosKernels::ArithTraits<scalar_type>::val_type impl_scalar_type;
328 typedef typename KokkosKernels::ArithTraits<impl_scalar_type>::mag_type magnitude_type;
329
330 typedef typename BlockTridiagScalarType<impl_scalar_type>::type btdm_scalar_type;
331 typedef typename KokkosKernels::ArithTraits<btdm_scalar_type>::mag_type btdm_magnitude_type;
332
336 typedef Kokkos::DefaultHostExecutionSpace host_execution_space;
337
341 typedef typename node_type::device_type node_device_type;
342 typedef typename node_device_type::execution_space node_execution_space;
343 typedef typename node_device_type::memory_space node_memory_space;
344
345#if defined(KOKKOS_ENABLE_CUDA) && defined(IFPACK2_BLOCKHELPER_USE_CUDA_SPACE)
347 typedef node_execution_space execution_space;
348 typedef typename std::conditional<std::is_same<node_memory_space, Kokkos::CudaUVMSpace>::value,
349 Kokkos::CudaSpace,
350 node_memory_space>::type memory_space;
351 typedef Kokkos::Device<execution_space, memory_space> device_type;
352#else
353 typedef node_device_type device_type;
354 typedef node_execution_space execution_space;
355 typedef node_memory_space memory_space;
356#endif
357
358 typedef Tpetra::MultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type> tpetra_multivector_type;
359 typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> tpetra_map_type;
360 typedef Tpetra::Import<local_ordinal_type, global_ordinal_type, node_type> tpetra_import_type;
361 typedef Tpetra::RowMatrix<scalar_type, local_ordinal_type, global_ordinal_type, node_type> tpetra_row_matrix_type;
362 typedef Tpetra::CrsMatrix<scalar_type, local_ordinal_type, global_ordinal_type, node_type> tpetra_crs_matrix_type;
363 typedef Tpetra::CrsGraph<local_ordinal_type, global_ordinal_type, node_type> tpetra_crs_graph_type;
364 typedef Tpetra::BlockCrsMatrix<scalar_type, local_ordinal_type, global_ordinal_type, node_type> tpetra_block_crs_matrix_type;
365 typedef typename tpetra_block_crs_matrix_type::little_block_type tpetra_block_access_view_type;
366 typedef Tpetra::BlockMultiVector<scalar_type, local_ordinal_type, global_ordinal_type, node_type> tpetra_block_multivector_type;
367 typedef typename tpetra_block_crs_matrix_type::crs_graph_type::local_graph_device_type local_crs_graph_type;
368
372 template <typename T, int l>
373 using Vector = KB::Vector<T, l>;
374 template <typename T>
375 using SIMD = KB::SIMD<T>;
376 template <typename T, typename M>
377 using DefaultVectorLength = KB::DefaultVectorLength<T, M>;
378 template <typename T, typename M>
379 using DefaultInternalVectorLength = KB::DefaultInternalVectorLength<T, M>;
380
381 static constexpr int vector_length = DefaultVectorLength<btdm_scalar_type, memory_space>::value;
382 static constexpr int internal_vector_length = DefaultInternalVectorLength<btdm_scalar_type, memory_space>::value;
383 static constexpr int half_vector_length = (vector_length > 1) ? (vector_length / 2) : 1;
384 typedef Vector<SIMD<btdm_scalar_type>, vector_length> vector_type;
385 typedef Vector<SIMD<btdm_scalar_type>, internal_vector_length> internal_vector_type;
386
390 typedef Kokkos::View<size_type *, device_type> size_type_1d_view;
391 typedef Kokkos::View<size_type **, device_type> size_type_2d_view;
392 typedef Kokkos::View<int64_t ***, Kokkos::LayoutRight, device_type> i64_3d_view;
393 typedef Kokkos::View<local_ordinal_type *, device_type> local_ordinal_type_1d_view;
394 typedef Kokkos::View<local_ordinal_type **, device_type> local_ordinal_type_2d_view;
395 // tpetra block crs values
396 typedef Kokkos::View<impl_scalar_type *, device_type> impl_scalar_type_1d_view;
397 typedef Kokkos::View<impl_scalar_type *, node_device_type> impl_scalar_type_1d_view_tpetra;
398
399 // tpetra multivector values (layout left): may need to change the typename more explicitly
400 typedef Kokkos::View<impl_scalar_type **, Kokkos::LayoutLeft, device_type> impl_scalar_type_2d_view;
401 typedef Kokkos::View<impl_scalar_type **, Kokkos::LayoutLeft, node_device_type> impl_scalar_type_2d_view_tpetra;
402 typedef Kokkos::View<const impl_scalar_type **, Kokkos::LayoutLeft, node_device_type> const_impl_scalar_type_2d_view_tpetra;
403
404 // packed data always use layout right
405 typedef Kokkos::View<vector_type *, device_type> vector_type_1d_view;
406 typedef Kokkos::View<vector_type ***, Kokkos::LayoutRight, device_type> vector_type_3d_view;
407 typedef Kokkos::View<vector_type ****, Kokkos::LayoutRight, device_type> vector_type_4d_view;
408 typedef Kokkos::View<internal_vector_type ***, Kokkos::LayoutRight, device_type> internal_vector_type_3d_view;
409 typedef Kokkos::View<internal_vector_type ****, Kokkos::LayoutRight, device_type> internal_vector_type_4d_view;
410 typedef Kokkos::View<internal_vector_type *****, Kokkos::LayoutRight, device_type> internal_vector_type_5d_view;
411 typedef Kokkos::View<btdm_scalar_type **, Kokkos::LayoutRight, device_type> btdm_scalar_type_2d_view;
412 typedef Kokkos::View<btdm_scalar_type ***, Kokkos::LayoutRight, device_type> btdm_scalar_type_3d_view;
413 typedef Kokkos::View<btdm_scalar_type ****, Kokkos::LayoutRight, device_type> btdm_scalar_type_4d_view;
414 typedef Kokkos::View<btdm_scalar_type *****, Kokkos::LayoutRight, device_type> btdm_scalar_type_5d_view;
415};
416
420template <typename MatrixType>
421struct AmD {
423 using local_ordinal_type_1d_view = typename impl_type::local_ordinal_type_1d_view;
424 using size_type_1d_view = typename impl_type::size_type_1d_view;
425 using i64_3d_view = typename impl_type::i64_3d_view;
426 using impl_scalar_type_1d_view_tpetra = Unmanaged<typename impl_type::impl_scalar_type_1d_view_tpetra>;
427 // rowptr points to the start of each row of A_colindsub.
428 size_type_1d_view rowptr, rowptr_remote;
429 // Indices into A's rows giving the blocks to extract. rowptr(i) points to
430 // the i'th row. Thus, g.entries(A_colindsub(rowptr(row) : rowptr(row+1))),
431 // where g is A's graph, are the columns AmD uses. If seq_method_, then
432 // A_colindsub contains all the LIDs and A_colindsub_remote is empty. If !
433 // seq_method_, then A_colindsub contains owned LIDs and A_colindsub_remote
434 // contains the remote ones.
435 local_ordinal_type_1d_view A_colindsub, A_colindsub_remote;
436 // Precomputed direct offsets to A,x blocks, for owned entries (OverlapTag case) or all entries (AsyncTag case)
437 i64_3d_view A_x_offsets;
438 // Precomputed direct offsets to A,x blocks, for non-owned entries (OverlapTag case). For AsyncTag case this is left empty.
439 i64_3d_view A_x_offsets_remote;
440
441 // Currently always true.
442 bool is_tpetra_block_crs;
443
444 // If is_tpetra_block_crs, then this is a pointer to A_'s value data.
445 impl_scalar_type_1d_view_tpetra tpetra_values;
446
447 AmD() = default;
448 AmD(const AmD &b) = default;
449};
450
451template <typename MatrixType>
452struct PartInterface {
453 using local_ordinal_type = typename BlockHelperDetails::ImplType<MatrixType>::local_ordinal_type;
454 using local_ordinal_type_1d_view = typename BlockHelperDetails::ImplType<MatrixType>::local_ordinal_type_1d_view;
455 using local_ordinal_type_2d_view = typename BlockHelperDetails::ImplType<MatrixType>::local_ordinal_type_2d_view;
456
457 PartInterface() = default;
458 PartInterface(const PartInterface &b) = default;
459
460 // Some terms:
461 // The matrix A is split as A = D + R, where D is the matrix of tridiag
462 // blocks and R is the remainder.
463 // A part is roughly a synonym for a tridiag. The distinction is that a part
464 // is the set of rows belonging to one tridiag and, equivalently, the off-diag
465 // rows in R associated with that tridiag. In contrast, the term tridiag is
466 // used to refer specifically to tridiag data, such as the pointer into the
467 // tridiag data array.
468 // Local (lcl) row are the LIDs. lclrow lists the LIDs belonging to each
469 // tridiag, and partptr points to the beginning of each tridiag. This is the
470 // LID space.
471 // Row index (idx) is the ordinal in the tridiag ordering. lclrow is indexed
472 // by this ordinal. This is the 'index' space.
473 // A flat index is the mathematical index into an array. A pack index
474 // accounts for SIMD packing.
475
476 // Local row LIDs. Permutation from caller's index space to tridiag index
477 // space.
478 local_ordinal_type_1d_view lclrow;
479 // partptr_ is the pointer array into lclrow_.
480 local_ordinal_type_1d_view partptr; // np+1
481 local_ordinal_type_2d_view partptr_sub;
482 local_ordinal_type_1d_view partptr_schur;
483 // packptr_(i), for i the pack index, indexes partptr_. partptr_(packptr_(i))
484 // is the start of the i'th pack.
485 local_ordinal_type_1d_view packptr; // npack+1
486 local_ordinal_type_1d_view packptr_sub;
487 local_ordinal_type_1d_view packindices_sub;
488 local_ordinal_type_2d_view packindices_schur;
489 // part2rowidx0_(i) is the flat row index of the start of the i'th part. It's
490 // an alias of partptr_ in the case of no overlap.
491 local_ordinal_type_1d_view part2rowidx0; // np+1
492 local_ordinal_type_1d_view part2rowidx0_sub;
493 // part2packrowidx0_(i) is the packed row index. If vector_length is 1, then
494 // it's the same as part2rowidx0_; if it's > 1, then the value is combined
495 // with i % vector_length to get the location in the packed data.
496 local_ordinal_type_1d_view part2packrowidx0; // np+1
497 local_ordinal_type_2d_view part2packrowidx0_sub;
498 local_ordinal_type part2packrowidx0_back; // So we don't need to grab the array from the GPU.
499 // rowidx2part_ maps the row index to the part index.
500 local_ordinal_type_1d_view rowidx2part; // nr
501 local_ordinal_type_1d_view rowidx2part_sub;
502 // True if lcl{row|col} is at most a constant away from row{idx|col}. In
503 // practice, this knowledge is not particularly useful, as packing for batched
504 // processing is done at the same time as the permutation from LID to index
505 // space. But it's easy to detect, so it's recorded in case an optimization
506 // can be made based on it.
507 bool row_contiguous;
508
509 local_ordinal_type max_partsz;
510 local_ordinal_type max_subpartsz;
511 local_ordinal_type n_subparts_per_part;
512 local_ordinal_type nparts;
513};
514
518template <typename MatrixType>
519struct NormManager {
520 public:
521 using impl_type = ImplType<MatrixType>;
522 using host_execution_space = typename impl_type::host_execution_space;
523 using magnitude_type = typename impl_type::magnitude_type;
524
525 private:
526 bool collective_;
527 int sweep_step_, sweep_step_upper_bound_;
528#ifdef HAVE_IFPACK2_MPI
529 MPI_Request mpi_request_;
530 MPI_Comm comm_;
531#endif
532 magnitude_type work_[3];
533
534 public:
535 NormManager() = default;
536 NormManager(const NormManager &b) = default;
537 NormManager(const Teuchos::RCP<const Teuchos::Comm<int>> &comm) {
538 sweep_step_ = 1;
539 sweep_step_upper_bound_ = 1;
540 collective_ = comm->getSize() > 1;
541 if (collective_) {
542#ifdef HAVE_IFPACK2_MPI
543 const auto mpi_comm = Teuchos::rcp_dynamic_cast<const Teuchos::MpiComm<int>>(comm);
544 TEUCHOS_ASSERT(!mpi_comm.is_null());
545 comm_ = *mpi_comm->getRawMpiComm();
546#endif
547 }
548 const magnitude_type zero(0), minus_one(-1);
549 work_[0] = zero;
550 work_[1] = zero;
551 work_[2] = minus_one;
552 }
553
554 // Check the norm every sweep_step sweeps.
555 void setCheckFrequency(const int sweep_step) {
556 TEUCHOS_TEST_FOR_EXCEPT_MSG(sweep_step < 1, "sweep step must be >= 1");
557 sweep_step_upper_bound_ = sweep_step;
558 sweep_step_ = 1;
559 }
560
561 // Get the buffer into which to store rank-local squared norms.
562 magnitude_type *getBuffer() { return &work_[0]; }
563
564 // Call MPI_Iallreduce to find the global squared norms.
565 void ireduce(const int sweep, const bool force = false) {
566 if (!force && sweep % sweep_step_) return;
567
568 IFPACK2_BLOCKHELPER_TIMER("BlockTriDi::NormManager::Ireduce", Ireduce);
569
570 work_[1] = work_[0];
571#ifdef HAVE_IFPACK2_MPI
572 auto send_data = &work_[1];
573 auto recv_data = &work_[0];
574 if (collective_) {
575#if defined(IFPACK2_BLOCKTRIDICONTAINER_USE_MPI_3)
576 MPI_Iallreduce(send_data, recv_data, 1,
577 Teuchos::Details::MpiTypeTraits<magnitude_type>::getType(),
578 MPI_SUM, comm_, &mpi_request_);
579#else
580 MPI_Allreduce(send_data, recv_data, 1,
581 Teuchos::Details::MpiTypeTraits<magnitude_type>::getType(),
582 MPI_SUM, comm_);
583#endif
584 }
585#endif
586 }
587
588 // Check if the norm-based termination criterion is met. tol2 is the
589 // tolerance squared. Sweep is the sweep index. If not every iteration is
590 // being checked, this function immediately returns false. If a check must
591 // be done at this iteration, it waits for the reduction triggered by
592 // ireduce to complete, then checks the global norm against the tolerance.
593 bool checkDone(const int sweep, const magnitude_type tol2, const bool force = false) {
594 // early return
595 if (sweep <= 0) return false;
596
597 IFPACK2_BLOCKHELPER_TIMER("BlockTriDi::NormManager::CheckDone", CheckDone);
598
599 TEUCHOS_ASSERT(sweep >= 1);
600 if (!force && (sweep - 1) % sweep_step_) return false;
601 if (collective_) {
602#ifdef HAVE_IFPACK2_MPI
603#if defined(IFPACK2_BLOCKTRIDICONTAINER_USE_MPI_3)
604 MPI_Wait(&mpi_request_, MPI_STATUS_IGNORE);
605#else
606 // Do nothing.
607#endif
608#endif
609 }
610 bool r_val = false;
611 if (sweep == 1) {
612 work_[2] = work_[0];
613 } else {
614 r_val = (work_[0] < tol2 * work_[2]);
615 }
616
617 // adjust sweep step
618 const auto adjusted_sweep_step = 2 * sweep_step_;
619 if (adjusted_sweep_step < sweep_step_upper_bound_) {
620 sweep_step_ = adjusted_sweep_step;
621 } else {
622 sweep_step_ = sweep_step_upper_bound_;
623 }
624 return r_val;
625 }
626
627 // After termination has occurred, finalize the norms for use in
628 // get_norms{0,final}.
629 void finalize() {
630 work_[0] = std::sqrt(work_[0]); // after converged
631 if (work_[2] >= 0)
632 work_[2] = std::sqrt(work_[2]); // first norm
633 // if work_[2] is minus one, then norm is not requested.
634 }
635
636 // Report norms to the caller.
637 const magnitude_type getNorms0() const { return work_[2]; }
638 const magnitude_type getNormsFinal() const { return work_[0]; }
639};
640
641template <typename MatrixType>
642void reduceVector(const ConstUnmanaged<typename BlockHelperDetails::ImplType<MatrixType>::impl_scalar_type_1d_view> zz,
643 /* */ typename BlockHelperDetails::ImplType<MatrixType>::magnitude_type *vals) {
644 IFPACK2_BLOCKHELPER_PROFILER_REGION_BEGIN;
645 IFPACK2_BLOCKHELPER_TIMER("BlockTriDi::ReduceVector", ReduceVector);
646
647 using impl_type = BlockHelperDetails::ImplType<MatrixType>;
648 using local_ordinal_type = typename impl_type::local_ordinal_type;
649 using impl_scalar_type = typename impl_type::impl_scalar_type;
650#if 0
651 const auto norm2 = KokkosBlas::nrm1(zz);
652#else
653 impl_scalar_type norm2(0);
654 Kokkos::parallel_reduce(
655 "ReduceMultiVector::Device",
656 Kokkos::RangePolicy<typename impl_type::execution_space>(0, zz.extent(0)),
657 KOKKOS_LAMBDA(const local_ordinal_type &i, impl_scalar_type &update) {
658 update += zz(i);
659 },
660 norm2);
661#endif
662 vals[0] = KokkosKernels::ArithTraits<impl_scalar_type>::abs(norm2);
663
664 IFPACK2_BLOCKHELPER_PROFILER_REGION_END;
665 IFPACK2_BLOCKHELPER_TIMER_FENCE(typename ImplType<MatrixType>::execution_space)
666}
667
668} // namespace BlockHelperDetails
669
670} // namespace Ifpack2
671
672#endif
Preconditioners and smoothers for Tpetra sparse matrices.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:40
Definition Ifpack2_BlockHelper.hpp:254
Definition Ifpack2_BlockHelper.hpp:123
Definition Ifpack2_BlockHelper.hpp:185
Definition Ifpack2_BlockHelper.hpp:313
KB::Vector< T, l > Vector
Definition Ifpack2_BlockHelper.hpp:373
size_t size_type
Definition Ifpack2_BlockHelper.hpp:317
node_type::device_type node_device_type
Definition Ifpack2_BlockHelper.hpp:341
Kokkos::DefaultHostExecutionSpace host_execution_space
Definition Ifpack2_BlockHelper.hpp:336
KokkosKernels::ArithTraits< scalar_type >::val_type impl_scalar_type
Definition Ifpack2_BlockHelper.hpp:327
Kokkos::View< size_type *, device_type > size_type_1d_view
Definition Ifpack2_BlockHelper.hpp:390
Definition Ifpack2_BlockHelper.hpp:107
Definition Ifpack2_BlockHelper.hpp:138
Definition Ifpack2_BlockHelper.hpp:152
Definition Ifpack2_BlockHelper.hpp:166