10#ifndef TPETRA_DETAILS_RESIDUAL_HPP
11#define TPETRA_DETAILS_RESIDUAL_HPP
13#include "TpetraCore_config.h"
14#include "Tpetra_CrsMatrix.hpp"
15#include "Tpetra_LocalCrsMatrixOperator.hpp"
16#include "Tpetra_MultiVector.hpp"
17#include "Teuchos_RCP.hpp"
18#include "Teuchos_ScalarTraits.hpp"
21#include "KokkosSparse_spmv_impl.hpp"
38template <
class AMatrix,
class MV,
class ConstMV,
class Offsets,
bool is_MV,
bool restrictedMode,
bool skipOffRank>
39struct LocalResidualFunctor {
40 using execution_space =
typename AMatrix::execution_space;
41 using LO =
typename AMatrix::non_const_ordinal_type;
42 using value_type =
typename AMatrix::non_const_value_type;
43 using team_policy =
typename Kokkos::TeamPolicy<execution_space>;
44 using team_member =
typename team_policy::member_type;
45 using ATV = KokkosKernels::ArithTraits<value_type>;
53 ConstMV X_domainmap_lcl;
55 LocalResidualFunctor(
const AMatrix& A_lcl_,
56 const ConstMV& X_colmap_lcl_,
57 const ConstMV& B_lcl_,
59 const int rows_per_team_,
60 const Offsets& offsets_,
61 const ConstMV& X_domainmap_lcl_)
63 , X_colmap_lcl(X_colmap_lcl_)
66 , rows_per_team(rows_per_team_)
68 , X_domainmap_lcl(X_domainmap_lcl_) {}
70 KOKKOS_INLINE_FUNCTION
71 void operator()(
const team_member& dev)
const {
72 Kokkos::parallel_for(Kokkos::TeamThreadRange(dev, 0, rows_per_team), [&](
const LO& loop) {
73 const LO lclRow =
static_cast<LO
>(dev.league_rank()) * rows_per_team + loop;
75 if (lclRow >= A_lcl.numRows()) {
81 value_type A_x = ATV::zero();
83 if (!restrictedMode) {
84 const auto A_row = A_lcl.rowConst(lclRow);
85 const LO row_length =
static_cast<LO
>(A_row.length);
87 Kokkos::parallel_reduce(
88 Kokkos::ThreadVectorRange(dev, row_length), [&](
const LO iEntry, value_type& lsum) {
89 const auto A_val = A_row.value(iEntry);
90 lsum += A_val * X_colmap_lcl(A_row.colidx(iEntry), 0);
95 const LO offRankOffset = offsets(lclRow);
96 const size_t start = A_lcl.graph.row_map(lclRow);
97 const size_t end = A_lcl.graph.row_map(lclRow + 1);
99 Kokkos::parallel_reduce(
100 Kokkos::ThreadVectorRange(dev, start, end), [&](
const LO iEntry, value_type& lsum) {
101 const auto A_val = A_lcl.values(iEntry);
102 const auto lclCol = A_lcl.graph.entries(iEntry);
103 if (iEntry < offRankOffset)
104 lsum += A_val * X_domainmap_lcl(lclCol, 0);
105 else if (!skipOffRank)
106 lsum += A_val * X_colmap_lcl(lclCol, 0);
111 Kokkos::single(Kokkos::PerThread(dev), [&]() {
112 R_lcl(lclRow, 0) = B_lcl(lclRow, 0) - A_x;
116 const LO numVectors =
static_cast<LO
>(X_colmap_lcl.extent(1));
118 for (LO v = 0; v < numVectors; v++) {
119 value_type A_x = ATV::zero();
121 if (!restrictedMode) {
122 const auto A_row = A_lcl.rowConst(lclRow);
123 const LO row_length =
static_cast<LO
>(A_row.length);
125 Kokkos::parallel_reduce(
126 Kokkos::ThreadVectorRange(dev, row_length), [&](
const LO iEntry, value_type& lsum) {
127 const auto A_val = A_row.value(iEntry);
128 lsum += A_val * X_colmap_lcl(A_row.colidx(iEntry), v);
132 const LO offRankOffset = offsets(lclRow);
133 const size_t start = A_lcl.graph.row_map(lclRow);
134 const size_t end = A_lcl.graph.row_map(lclRow + 1);
136 Kokkos::parallel_reduce(
137 Kokkos::ThreadVectorRange(dev, start, end), [&](
const LO iEntry, value_type& lsum) {
138 const auto A_val = A_lcl.values(iEntry);
139 const auto lclCol = A_lcl.graph.entries(iEntry);
140 if (iEntry < offRankOffset)
141 lsum += A_val * X_domainmap_lcl(lclCol, v);
142 else if (!skipOffRank)
143 lsum += A_val * X_colmap_lcl(lclCol, v);
148 Kokkos::single(Kokkos::PerThread(dev), [&]() {
149 R_lcl(lclRow, v) = B_lcl(lclRow, v) - A_x;
159template <
class AMatrix,
class MV,
class ConstMV,
class Offsets,
bool is_MV>
160struct OffRankUpdateFunctor {
161 using execution_space =
typename AMatrix::execution_space;
162 using LO =
typename AMatrix::non_const_ordinal_type;
163 using value_type =
typename AMatrix::non_const_value_type;
164 using team_policy =
typename Kokkos::TeamPolicy<execution_space>;
165 using team_member =
typename team_policy::member_type;
166 using ATV = KokkosKernels::ArithTraits<value_type>;
169 ConstMV X_colmap_lcl;
174 OffRankUpdateFunctor(
const AMatrix& A_lcl_,
175 const ConstMV& X_colmap_lcl_,
177 const int rows_per_team_,
178 const Offsets& offsets_)
180 , X_colmap_lcl(X_colmap_lcl_)
182 , rows_per_team(rows_per_team_)
183 , offsets(offsets_) {}
185 KOKKOS_INLINE_FUNCTION
186 void operator()(
const team_member& dev)
const {
187 Kokkos::parallel_for(Kokkos::TeamThreadRange(dev, 0, rows_per_team), [&](
const LO& loop) {
188 const LO lclRow =
static_cast<LO
>(dev.league_rank()) * rows_per_team + loop;
190 if (lclRow >= A_lcl.numRows()) {
194 const LO offRankOffset = offsets(lclRow);
195 const size_t end = A_lcl.graph.row_map(lclRow + 1);
199 value_type A_x = ATV::zero();
201 Kokkos::parallel_reduce(
202 Kokkos::ThreadVectorRange(dev, offRankOffset, end), [&](
const LO iEntry, value_type& lsum) {
203 const auto A_val = A_lcl.values(iEntry);
204 const auto lclCol = A_lcl.graph.entries(iEntry);
205 lsum += A_val * X_colmap_lcl(lclCol, 0);
209 Kokkos::single(Kokkos::PerThread(dev), [&]() {
210 R_lcl(lclRow, 0) -= A_x;
214 const LO numVectors =
static_cast<LO
>(X_colmap_lcl.extent(1));
216 for (LO v = 0; v < numVectors; v++) {
217 value_type A_x = ATV::zero();
219 Kokkos::parallel_reduce(
220 Kokkos::ThreadVectorRange(dev, offRankOffset, end), [&](
const LO iEntry, value_type& lsum) {
221 const auto A_val = A_lcl.values(iEntry);
222 const auto lclCol = A_lcl.graph.entries(iEntry);
223 lsum += A_val * X_colmap_lcl(lclCol, v);
227 Kokkos::single(Kokkos::PerThread(dev), [&]() {
228 R_lcl(lclRow, v) -= A_x;
237template <
class SC,
class LO,
class GO,
class NO>
242 const Kokkos::View<const size_t*, typename NO::device_type>& offsets,
244 using Teuchos::NO_TRANS;
251 using offset_type = Kokkos::View<const size_t*, typename NO::device_type>;
254 const_local_view_device_type X_colmap_lcl = X_colmap.
getLocalViewDevice(Access::ReadOnly);
257 const_local_view_device_type X_domainmap_lcl;
263 "R.getNumVectors() = "
268 "X has the wrong number of local rows. "
269 "X.getLocalLength() = "
271 "A.getColMap()->getLocalNumElements() = "
272 << A.
getColMap()->getLocalNumElements() <<
".");
276 "R has the wrong number of local rows. "
277 "R.getLocalLength() = "
279 "A.getRowMap()->getLocalNumElements() = "
280 << A.
getRowMap()->getLocalNumElements() <<
".");
284 "B has the wrong number of local rows. "
285 "B.getLocalLength() = "
287 "A.getRowMap()->getLocalNumElements() = "
288 << A.
getRowMap()->getLocalNumElements() <<
".");
290 TEUCHOS_TEST_FOR_EXCEPTION(!A.
isFillComplete(), std::runtime_error,
291 "The matrix A is not "
292 "fill complete. You must call fillComplete() (possibly with "
293 "domain and range Map arguments) without an intervening "
294 "resumeFill() call before you may call this method.");
296 std::runtime_error,
"X, Y and B must be constant stride.");
299 TEUCHOS_TEST_FOR_EXCEPTION((X_colmap_lcl.data() == R_lcl.data() && X_colmap_lcl.data() !=
nullptr) ||
300 (X_colmap_lcl.data() == B_lcl.data() && X_colmap_lcl.data() !=
nullptr),
301 std::runtime_error,
"X, Y and R may not alias one another.");
305 if (!fusedResidual) {
306 SC one = Teuchos::ScalarTraits<SC>::one();
308 SC zero = Teuchos::ScalarTraits<SC>::zero();
311 A.
localApply(X_colmap, R, Teuchos::NO_TRANS, one, zero);
316 if (A_lcl.numRows() == 0) {
320 int64_t numLocalRows = A_lcl.numRows();
321 int64_t myNnz = A_lcl.nnz();
324 int vector_length = -1;
325 int64_t rows_per_thread = -1;
328 using policy_type =
typename Kokkos::TeamPolicy<execution_space>;
330 int64_t rows_per_team = KokkosSparse::Impl::spmv_launch_parameters<execution_space>(numLocalRows, myNnz, rows_per_thread, team_size, vector_length);
331 int64_t worksets = (B_lcl.extent(0) + rows_per_team - 1) / rows_per_team;
333 policy_type policy(1, 1);
335 policy = policy_type(worksets, Kokkos::AUTO, vector_length);
337 policy = policy_type(worksets, team_size, vector_length);
340 bool is_vector = (X_colmap_lcl.extent(1) == 1);
343 if (X_domainmap ==
nullptr) {
345 functor_type func(A_lcl, X_colmap_lcl, B_lcl, R_lcl, rows_per_team, offsets, X_domainmap_lcl);
346 Kokkos::parallel_for(
"residual-vector", policy, func);
349 X_domainmap_lcl = X_domainmap->getLocalViewDevice(Access::ReadOnly);
351 functor_type func(A_lcl, X_colmap_lcl, B_lcl, R_lcl, rows_per_team, offsets, X_domainmap_lcl);
352 Kokkos::parallel_for(
"residual-vector", policy, func);
355 if (X_domainmap ==
nullptr) {
357 functor_type func(A_lcl, X_colmap_lcl, B_lcl, R_lcl, rows_per_team, offsets, X_domainmap_lcl);
358 Kokkos::parallel_for(
"residual-multivector", policy, func);
361 X_domainmap_lcl = X_domainmap->getLocalViewDevice(Access::ReadOnly);
363 functor_type func(A_lcl, X_colmap_lcl, B_lcl, R_lcl, rows_per_team, offsets, X_domainmap_lcl);
364 Kokkos::parallel_for(
"residual-multivector", policy, func);
369template <
class SC,
class LO,
class GO,
class NO>
370void localResidualWithCommCompOverlap(
const CrsMatrix<SC, LO, GO, NO>& A,
371 MultiVector<SC, LO, GO, NO>& X_colmap,
372 const MultiVector<SC, LO, GO, NO>& B,
373 MultiVector<SC, LO, GO, NO>& R,
374 const Kokkos::View<const size_t*, typename NO::device_type>& offsets,
375 const MultiVector<SC, LO, GO, NO>& X_domainmap) {
376 using Teuchos::NO_TRANS;
378 using Tpetra::Details::ProfilingRegion;
381 ProfilingRegion regionLocalApply(
"Tpetra::CrsMatrix::localResidualWithCommCompOverlap");
384 using local_view_device_type =
typename MultiVector<SC, LO, GO, NO>::dual_view_type::t_dev::non_const_type;
385 using const_local_view_device_type =
typename MultiVector<SC, LO, GO, NO>::dual_view_type::t_dev::const_type;
386 using offset_type = Kokkos::View<const size_t*, typename NO::device_type>;
389 const_local_view_device_type X_colmap_lcl = X_colmap.getLocalViewDevice(Access::ReadOnly);
390 const_local_view_device_type B_lcl = B.getLocalViewDevice(Access::ReadOnly);
391 local_view_device_type R_lcl = R.getLocalViewDevice(Access::OverwriteAll);
392 const_local_view_device_type X_domainmap_lcl = X_domainmap.getLocalViewDevice(Access::ReadOnly);
397 TEUCHOS_TEST_FOR_EXCEPTION(X_colmap.getNumVectors() != R.getNumVectors(), std::runtime_error,
398 "X.getNumVectors() = " << X_colmap.getNumVectors() <<
" != "
399 "R.getNumVectors() = "
400 << R.getNumVectors() <<
".");
401 TEUCHOS_TEST_FOR_EXCEPTION(X_colmap.getLocalLength() !=
402 A.getColMap()->getLocalNumElements(),
404 "X has the wrong number of local rows. "
405 "X.getLocalLength() = "
406 << X_colmap.getLocalLength() <<
" != "
407 "A.getColMap()->getLocalNumElements() = "
408 << A.getColMap()->getLocalNumElements() <<
".");
409 TEUCHOS_TEST_FOR_EXCEPTION(R.getLocalLength() !=
410 A.getRowMap()->getLocalNumElements(),
412 "R has the wrong number of local rows. "
413 "R.getLocalLength() = "
414 << R.getLocalLength() <<
" != "
415 "A.getRowMap()->getLocalNumElements() = "
416 << A.getRowMap()->getLocalNumElements() <<
".");
417 TEUCHOS_TEST_FOR_EXCEPTION(B.getLocalLength() !=
418 A.getRowMap()->getLocalNumElements(),
420 "B has the wrong number of local rows. "
421 "B.getLocalLength() = "
422 << B.getLocalLength() <<
" != "
423 "A.getRowMap()->getLocalNumElements() = "
424 << A.getRowMap()->getLocalNumElements() <<
".");
426 TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete(), std::runtime_error,
427 "The matrix A is not "
428 "fill complete. You must call fillComplete() (possibly with "
429 "domain and range Map arguments) without an intervening "
430 "resumeFill() call before you may call this method.");
431 TEUCHOS_TEST_FOR_EXCEPTION(!X_colmap.isConstantStride() || !R.isConstantStride() || !B.isConstantStride(),
432 std::runtime_error,
"X, Y and B must be constant stride.");
435 TEUCHOS_TEST_FOR_EXCEPTION((X_colmap_lcl.data() == R_lcl.data() && X_colmap_lcl.data() !=
nullptr) ||
436 (X_colmap_lcl.data() == B_lcl.data() && X_colmap_lcl.data() !=
nullptr),
437 std::runtime_error,
"X, Y and R may not alias one another.");
440 if (A_lcl.numRows() == 0) {
444 int64_t numLocalRows = A_lcl.numRows();
445 int64_t myNnz = A_lcl.nnz();
448 int vector_length = -1;
449 int64_t rows_per_thread = -1;
452 using policy_type =
typename Kokkos::TeamPolicy<execution_space>;
454 int64_t rows_per_team = KokkosSparse::Impl::spmv_launch_parameters<execution_space>(numLocalRows, myNnz, rows_per_thread, team_size, vector_length);
455 int64_t worksets = (B_lcl.extent(0) + rows_per_team - 1) / rows_per_team;
457 policy_type policy(1, 1);
459 policy = policy_type(worksets, Kokkos::AUTO, vector_length);
461 policy = policy_type(worksets, team_size, vector_length);
464 bool is_vector = (X_colmap_lcl.extent(1) == 1);
468 functor_type func(A_lcl, X_colmap_lcl, B_lcl, R_lcl, rows_per_team, offsets, X_domainmap_lcl);
469 Kokkos::parallel_for(
"residual-vector", policy, func);
471 RCP<const import_type> importer = A.getGraph()->getImporter();
472 X_colmap.endImport(X_domainmap, *importer,
INSERT,
true);
474 Kokkos::fence(
"Tpetra::localResidualWithCommCompOverlap-1");
477 functor_type2 func2(A_lcl, X_colmap_lcl, R_lcl, rows_per_team, offsets);
478 Kokkos::parallel_for(
"residual-vector-offrank", policy, func2);
482 functor_type func(A_lcl, X_colmap_lcl, B_lcl, R_lcl, rows_per_team, offsets, X_domainmap_lcl);
483 Kokkos::parallel_for(
"residual-multivector", policy, func);
485 RCP<const import_type> importer = A.getGraph()->getImporter();
486 X_colmap.endImport(X_domainmap, *importer,
INSERT,
true);
488 Kokkos::fence(
"Tpetra::localResidualWithCommCompOverlap-2");
491 functor_type2 func2(A_lcl, X_colmap_lcl, R_lcl, rows_per_team, offsets);
492 Kokkos::parallel_for(
"residual-vector-offrank", policy, func2);
497template <
class SC,
class LO,
class GO,
class NO>
504 using Teuchos::rcp_const_cast;
505 using Teuchos::rcpFromRef;
511 if (overlapCommunicationAndComputation)
512 TEUCHOS_ASSERT(skipCopyAndPermuteIfPossible);
519 bool restrictedMode =
false;
524 SC one = Teuchos::ScalarTraits<SC>::one(), negone = -one, zero = Teuchos::ScalarTraits<SC>::zero();
525 Aop.
apply(X_in, R_in, Teuchos::NO_TRANS, one, zero);
526 R_in.
update(one, B_in, negone);
535 using offset_type =
typename graph_type::offset_device_view_type;
538 const bool R_is_replicated =
547 RCP<const import_type> importer = A.
getGraph()->getImporter();
548 RCP<const export_type> exporter = A.
getGraph()->getExporter();
554 if (importer.is_null()) {
568 X_colMap = rcp_const_cast<MV>(rcpFromRef(X_in));
579 restrictedMode = skipCopyAndPermuteIfPossible && importer->isLocallyFitted();
581 if (debug && restrictedMode) {
582 TEUCHOS_TEST_FOR_EXCEPTION(!importer->getTargetMap()->isLocallyFitted(*importer->getSourceMap()), std::runtime_error,
583 "Source map and target map are not locally fitted, but Tpetra::residual thinks they are.");
587 X_colMap->beginImport(X_in, *importer,
INSERT, restrictedMode);
598 if (exporter.is_null()) {
602 R_rowMap = rcpFromRef(R_in);
610 RCP<const MV> B_rowMap;
611 if (exporter.is_null()) {
617 B_rowMap = rcp_const_cast<const MV>(B_rowMapNonConst);
619 B_rowMap = rcpFromRef(B_in);
626 B_rowMapNonConst->doImport(B_in, *exporter,
ADD);
627 B_rowMap = rcp_const_cast<const MV>(B_rowMapNonConst);
635 if (!exporter.is_null()) {
636 if (!importer.is_null())
637 X_colMap->endImport(X_in, *importer,
INSERT, restrictedMode);
638 if (restrictedMode && !importer.is_null())
639 localResidual(A, *X_colMap, *B_rowMap, *R_rowMap, offsets, &X_in);
641 localResidual(A, *X_colMap, *B_rowMap, *R_rowMap, offsets);
652 if (overlapCommunicationAndComputation) {
653 localResidualWithCommCompOverlap(A, *X_colMap, *B_rowMap, *R_rowMap, offsets, X_in);
655 X_colMap->endImport(X_in, *importer,
INSERT, restrictedMode);
656 localResidual(A, *X_colMap, *B_rowMap, *R_rowMap, offsets, &X_in);
659 if (!importer.is_null())
660 X_colMap->endImport(X_in, *importer,
INSERT, restrictedMode);
661 localResidual(A, *X_colMap, *B_rowMap, *R_rowMap, offsets);
678 if (R_is_replicated) {
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.
Declaration of Tpetra::Details::Profiling, a scope guard for Kokkos Profiling.
A distributed graph accessed by rows (adjacency lists) and stored sparsely.
Sparse matrix that presents a row-oriented interface that lets users read or modify entries.
void localApply(const MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &X, MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Y, const Teuchos::ETransp mode=Teuchos::NO_TRANS, const Scalar &alpha=Teuchos::ScalarTraits< Scalar >::one(), const Scalar &beta=Teuchos::ScalarTraits< Scalar >::zero()) const
Compute the local part of a sparse matrix-(Multi)Vector multiply.
typename device_type::execution_space execution_space
The Kokkos execution space.
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const override
The communicator over which the matrix is distributed.
Teuchos::RCP< MV > getColumnMapMultiVector(const MV &X_domainMap, const bool force=false) const
Create a (or fetch a cached) column Map MultiVector.
Export< LocalOrdinal, GlobalOrdinal, Node > export_type
The Export specialization suitable for this CrsMatrix specialization.
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.
Teuchos::RCP< const RowGraph< LocalOrdinal, GlobalOrdinal, Node > > getGraph() const override
This matrix's graph, as a RowGraph.
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 isFillComplete() const override
Whether the matrix is fill complete.
Teuchos::RCP< const map_type > getRowMap() const override
The Map that describes the row distribution in this matrix.
Teuchos::RCP< MV > getRowMapMultiVector(const MV &Y_rangeMap, const bool force=false) const
Create a (or fetch a cached) row Map MultiVector.
Import< LocalOrdinal, GlobalOrdinal, Node > import_type
The Import specialization suitable for this CrsMatrix specialization.
Teuchos::RCP< const crs_graph_type > getCrsGraph() const
This matrix's graph, as a CrsGraph.
static bool fusedResidual()
Fusing SpMV and update in residual instead of using 2 kernel launches. Fusing kernels implies that no...
static bool debug()
Whether Tpetra is in debug mode.
static bool overlapCommunicationAndComputation()
Overlap communication and computation.
static bool skipCopyAndPermuteIfPossible()
Skip copyAndPermute if possible.
void doExport(const SrcDistObject &source, const Export< LocalOrdinal, GlobalOrdinal, Node > &exporter, const CombineMode CM, const bool restrictedMode=false)
Export data into this object using an Export object ("forward mode").
bool isDistributed() const
Whether this is a globally distributed object.
One or more distributed dense vectors.
void reduce()
Sum values of a locally replicated multivector across all processes.
size_t getLocalLength() const
Local number of rows on the calling process.
size_t getNumVectors() const
Number of columns in the multivector.
dual_view_type::t_dev::const_type getLocalViewDevice(Access::ReadOnlyStruct) const
Return a read-only, up-to-date view of this MultiVector's local data on device. This requires that th...
bool isConstantStride() const
Whether this multivector has constant stride between columns.
void update(const Scalar &alpha, const MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, const Scalar &beta)
Update: this = beta*this + alpha*A.
Abstract interface for operators (e.g., matrices and preconditioners).
virtual void apply(const MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &X, MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, Scalar alpha=Teuchos::ScalarTraits< Scalar >::one(), Scalar beta=Teuchos::ScalarTraits< Scalar >::zero()) const =0
Computes the operator-multivector application.
Nonmember function that computes a residual Computes R = B - A * X.
void residual(const Operator< SC, LO, GO, NO > &A, const MultiVector< SC, LO, GO, NO > &X, const MultiVector< SC, LO, GO, NO > &B, MultiVector< SC, LO, GO, NO > &R)
Computes R = B - A * X.
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.
@ INSERT
Insert new values that don't currently exist.
Functor for computing the residual.
Functor for computing R -= A_offRank*X_colmap.