48 #ifndef PACKAGES_XPETRA_SUP_UTILS_XPETRA_MATRIXMATRIX_HPP_
49 #define PACKAGES_XPETRA_SUP_UTILS_XPETRA_MATRIXMATRIX_HPP_
54 #include "Xpetra_CrsMatrixWrap.hpp"
55 #include "Xpetra_MapExtractor.hpp"
56 #include "Xpetra_Map.hpp"
59 #include "Xpetra_StridedMapFactory.hpp"
60 #include "Xpetra_StridedMap.hpp"
62 #ifdef HAVE_XPETRA_EPETRA
66 #ifdef HAVE_XPETRA_EPETRAEXT
67 #include <EpetraExt_MatrixMatrix.h>
68 #include <EpetraExt_RowMatrixOut.h>
69 #include <Epetra_RowMatrixTransposer.h>
70 #endif // HAVE_XPETRA_EPETRAEXT
72 #ifdef HAVE_XPETRA_TPETRA
73 #include <TpetraExt_MatrixMatrix.hpp>
74 #include <Tpetra_RowMatrixTransposer.hpp>
75 #include <MatrixMarket_Tpetra.hpp>
76 #include <Xpetra_TpetraCrsMatrix.hpp>
77 #include <Xpetra_TpetraBlockCrsMatrix.hpp>
78 #include <Tpetra_BlockCrsMatrix_Helpers.hpp>
79 #include <Xpetra_TpetraMultiVector.hpp>
80 #include <Xpetra_TpetraVector.hpp>
81 #endif // HAVE_XPETRA_TPETRA
91 template <
class Scalar,
92 class LocalOrdinal = int,
93 class GlobalOrdinal = LocalOrdinal,
94 class Node = Tpetra::KokkosClassic::DefaultNode::DefaultNodeType>
99 #ifdef HAVE_XPETRA_EPETRA
102 RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<
const CrsMatrixWrap>(Op);
104 "Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed");
106 RCP<const CrsMatrix> tmp_CrsMtx = crsOp->getCrsMatrix();
107 const RCP<const EpetraCrsMatrixT<GO, NO> >& tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<
const EpetraCrsMatrixT<GO, NO> >(tmp_CrsMtx);
109 "Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed");
111 return tmp_ECrsMtx->getEpetra_CrsMatrix();
115 RCP<Epetra_CrsMatrix> A;
117 RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<
const CrsMatrixWrap>(Op);
119 "Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed");
121 RCP<const CrsMatrix> tmp_CrsMtx = crsOp->getCrsMatrix();
122 const RCP<const EpetraCrsMatrixT<GO, NO> >& tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<
const EpetraCrsMatrixT<GO, NO> >(tmp_CrsMtx);
123 TEUCHOS_TEST_FOR_EXCEPTION(tmp_ECrsMtx == Teuchos::null,
Exceptions::BadCast,
"Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed");
125 return tmp_ECrsMtx->getEpetra_CrsMatrixNonConst();
133 const RCP<const EpetraCrsMatrixT<GO, NO> >& tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<
const EpetraCrsMatrixT<GO, NO> >(tmp_CrsMtx);
135 "Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed");
137 return *tmp_ECrsMtx->getEpetra_CrsMatrix();
145 RCP<Epetra_CrsMatrix> A;
150 const RCP<const EpetraCrsMatrixT<GO, NO> >& tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<
const EpetraCrsMatrixT<GO, NO> >(tmp_CrsMtx);
151 TEUCHOS_TEST_FOR_EXCEPTION(tmp_ECrsMtx == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed");
153 return *Teuchos::rcp_const_cast<Epetra_CrsMatrix>(tmp_ECrsMtx->getEpetra_CrsMatrix());
159 #endif // HAVE_XPETRA_EPETRA
161 #ifdef HAVE_XPETRA_TPETRA
162 static RCP<const Tpetra::CrsMatrix<SC, LO, GO, NO> >
Op2TpetraCrs(RCP<Matrix> Op) {
164 RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<
const CrsMatrixWrap>(Op);
165 TEUCHOS_TEST_FOR_EXCEPTION(crsOp == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed");
167 RCP<const CrsMatrix> tmp_CrsMtx = crsOp->getCrsMatrix();
169 TEUCHOS_TEST_FOR_EXCEPTION(tmp_ECrsMtx == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed");
171 return tmp_ECrsMtx->getTpetra_CrsMatrix();
176 RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<
const CrsMatrixWrap>(Op);
177 TEUCHOS_TEST_FOR_EXCEPTION(crsOp == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed");
178 RCP<const CrsMatrix> tmp_CrsMtx = crsOp->getCrsMatrix();
180 TEUCHOS_TEST_FOR_EXCEPTION(tmp_ECrsMtx == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed");
182 return tmp_ECrsMtx->getTpetra_CrsMatrixNonConst();
191 TEUCHOS_TEST_FOR_EXCEPTION(tmp_TCrsMtx == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed");
193 return *tmp_TCrsMtx->getTpetra_CrsMatrix();
206 TEUCHOS_TEST_FOR_EXCEPTION(tmp_TCrsMtx == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed");
208 return *Teuchos::rcp_const_cast<Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(tmp_TCrsMtx->getTpetra_CrsMatrix());
216 RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<
const CrsMatrixWrap>(Op);
217 if (crsOp == Teuchos::null)
return false;
218 RCP<const CrsMatrix> tmp_CrsMtx = crsOp->
getCrsMatrix();
220 if (tmp_ECrsMtx == Teuchos::null)
231 if (tmp_ECrsMtx == Teuchos::null)
241 RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<
const CrsMatrixWrap>(Op);
242 TEUCHOS_TEST_FOR_EXCEPTION(crsOp == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed");
244 RCP<const CrsMatrix> tmp_CrsMtx = crsOp->getCrsMatrix();
245 RCP<const TpetraBlockCrsMatrix> tmp_BlockCrs = Teuchos::rcp_dynamic_cast<
const TpetraBlockCrsMatrix>(tmp_CrsMtx);
246 TEUCHOS_TEST_FOR_EXCEPTION(tmp_BlockCrs == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::CrsMatrix to Xpetra::TpetraBlockCrsMatrix failed");
247 return tmp_BlockCrs->getTpetra_BlockCrsMatrix();
251 RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<
const CrsMatrixWrap>(Op);
252 TEUCHOS_TEST_FOR_EXCEPTION(crsOp == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed");
254 RCP<const CrsMatrix> tmp_CrsMtx = crsOp->getCrsMatrix();
255 RCP<const TpetraBlockCrsMatrix> tmp_BlockCrs = Teuchos::rcp_dynamic_cast<
const TpetraBlockCrsMatrix>(tmp_CrsMtx);
256 TEUCHOS_TEST_FOR_EXCEPTION(tmp_BlockCrs == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::CrsMatrix to Xpetra::TpetraBlockCrsMatrix failed");
257 return tmp_BlockCrs->getTpetra_BlockCrsMatrixNonConst();
264 RCP<const TpetraBlockCrsMatrix> tmp_BlockCrs = Teuchos::rcp_dynamic_cast<
const TpetraBlockCrsMatrix>(tmp_CrsMtx);
265 TEUCHOS_TEST_FOR_EXCEPTION(tmp_BlockCrs == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::CrsMatrix to Xpetra::TpetraBlockCrsMatrix failed");
266 return *tmp_BlockCrs->getTpetra_BlockCrsMatrix();
276 RCP<const TpetraBlockCrsMatrix> tmp_BlockCrs = Teuchos::rcp_dynamic_cast<
const TpetraBlockCrsMatrix>(tmp_CrsMtx);
277 TEUCHOS_TEST_FOR_EXCEPTION(tmp_BlockCrs == Teuchos::null,
Xpetra::Exceptions::BadCast,
"Cast from Xpetra::CrsMatrix to Xpetra::TpetraBlockCrsMatrix failed");
278 return *tmp_BlockCrs->getTpetra_BlockCrsMatrixNonConst();
285 RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<
const CrsMatrixWrap>(Op);
286 if (crsOp == Teuchos::null)
return false;
287 RCP<const CrsMatrix> tmp_CrsMtx = crsOp->
getCrsMatrix();
288 RCP<const TpetraBlockCrsMatrix> tmp_BlockCrs = Teuchos::rcp_dynamic_cast<
const TpetraBlockCrsMatrix>(tmp_CrsMtx);
289 if (tmp_BlockCrs == Teuchos::null)
299 RCP<const TpetraBlockCrsMatrix> tmp_BlockCrs = Teuchos::rcp_dynamic_cast<
const TpetraBlockCrsMatrix>(tmp_CrsMtx);
300 if (tmp_BlockCrs == Teuchos::null)
308 #else // HAVE_XPETRA_TPETRA
317 #endif // HAVE_XPETRA_TPETRA
319 #ifdef HAVE_XPETRA_TPETRA
322 const tcrs_matrix_type& A,
bool transposeA,
const typename tcrs_matrix_type::scalar_type alpha,
323 const tcrs_matrix_type& B,
bool transposeB,
const typename tcrs_matrix_type::scalar_type beta) {
324 using Teuchos::Array;
325 using Teuchos::ParameterList;
328 using Teuchos::rcp_implicit_cast;
329 using Teuchos::rcpFromRef;
333 using transposer_type = Tpetra::RowMatrixTransposer<SC, LO, GO, NO>;
334 using import_type = Tpetra::Import<LO, GO, NO>;
335 RCP<const tcrs_matrix_type> Aprime = rcpFromRef(A);
337 Aprime = transposer_type(Aprime).createTranspose();
339 if (A.isFillComplete() && B.isFillComplete()) {
340 RCP<tcrs_matrix_type> C = rcp(
new tcrs_matrix_type(Aprime->getRowMap(), 0));
341 RCP<ParameterList> addParams = rcp(
new ParameterList);
342 addParams->set(
"Call fillComplete",
false);
344 Tpetra::MatrixMatrix::add<SC, LO, GO, NO>(beta, transposeB, B, alpha,
false, *Aprime, *C, Teuchos::null, Teuchos::null, addParams);
345 return rcp_implicit_cast<
Matrix>(rcp(
new CrsWrap(rcp_implicit_cast<CrsType>(rcp(
new XTCrsType(C))))));
351 RCP<const tcrs_matrix_type> Bprime = rcpFromRef(B);
353 Bprime = transposer_type(Bprime).createTranspose();
355 if (!(Aprime->getRowMap()->isSameAs(*(Bprime->getRowMap())))) {
356 auto import = rcp(
new import_type(Bprime->getRowMap(), Aprime->getRowMap()));
357 Bprime = Tpetra::importAndFillCompleteCrsMatrix<tcrs_matrix_type>(Bprime, *
import, Aprime->getDomainMap(), Aprime->getRangeMap());
360 LO numLocalRows = Aprime->getLocalNumRows();
361 Array<size_t> allocPerRow(numLocalRows);
363 for (LO i = 0; i < numLocalRows; i++) {
364 allocPerRow[i] = Aprime->getNumEntriesInLocalRow(i) + Bprime->getNumEntriesInLocalRow(i);
367 RCP<tcrs_matrix_type> C = rcp(
new tcrs_matrix_type(Aprime->getRowMap(), allocPerRow()));
369 Tpetra::MatrixMatrix::Add<SC, LO, GO, NO>(
370 *Aprime,
false, alpha,
371 *Bprime,
false, beta,
373 return rcp(
new CrsWrap(rcp_implicit_cast<CrsType>(rcp(
new XTCrsType(C)))));
378 #ifdef HAVE_XPETRA_EPETRAEXT
385 const Epetra_Map& Crowmap = epC.RowMap();
387 Epetra_CrsMatrix Ctemp(::Copy, Crowmap, 0,
false);
388 if (fillCompleteResult) {
389 errCode = EpetraExt::MatrixMatrix::Multiply(epA, transposeA, epB, transposeB, Ctemp,
true);
395 errCode = EpetraExt::MatrixMatrix::Multiply(epA, transposeA, epB, transposeB, Ctemp,
false);
397 int numLocalRows = Crowmap.NumMyElements();
398 long long* globalElementList =
nullptr;
399 Crowmap.MyGlobalElementsPtr(globalElementList);
400 Teuchos::Array<int> entriesPerRow(numLocalRows, 0);
401 for (
int i = 0; i < numLocalRows; i++) {
402 entriesPerRow[i] = Ctemp.NumGlobalEntries(globalElementList[i]);
405 epC = Epetra_CrsMatrix(::Copy, Crowmap, entriesPerRow.data(),
true);
406 for (
int i = 0; i < numLocalRows; i++) {
407 int gid = globalElementList[i];
411 Ctemp.ExtractGlobalRowView(gid, numEntries, values, inds);
412 epC.InsertGlobalValues(gid, numEntries, values, inds);
417 std::ostringstream buf;
419 std::string msg =
"EpetraExt::MatrixMatrix::Multiply returned nonzero error code " + buf.str();
426 template <
class Scalar,
428 class GlobalOrdinal ,
431 #undef XPETRA_MATRIXMATRIX_SHORT
460 const Matrix& B,
bool transposeB,
462 bool call_FillComplete_on_result =
true,
463 bool doOptimizeStorage =
true,
464 const std::string& label = std::string(),
465 const RCP<ParameterList>& params = null) {
466 TEUCHOS_TEST_FOR_EXCEPTION(transposeA ==
false && C.
getRowMap()->isSameAs(*A.
getRowMap()) ==
false,
468 TEUCHOS_TEST_FOR_EXCEPTION(transposeA ==
true && C.
getRowMap()->isSameAs(*A.
getDomainMap()) ==
false,
474 bool haveMultiplyDoFillComplete = call_FillComplete_on_result && doOptimizeStorage;
477 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
478 throw(
Xpetra::Exceptions::RuntimeError(
"Xpetra::MatrixMatrix::Multiply only available for GO=int or GO=long long with EpetraNode (Serial or OpenMP depending on configuration)"));
484 #ifdef HAVE_XPETRA_TPETRA
486 if (helpers::isTpetraCrs(A) && helpers::isTpetraCrs(B) && helpers::isTpetraCrs(C)) {
488 const Tpetra::CrsMatrix<SC, LO, GO, NO>& tpA = helpers::Op2TpetraCrs(A);
489 const Tpetra::CrsMatrix<SC, LO, GO, NO>& tpB = helpers::Op2TpetraCrs(B);
490 Tpetra::CrsMatrix<SC, LO, GO, NO>& tpC = helpers::Op2NonConstTpetraCrs(C);
494 Tpetra::MatrixMatrix::Multiply(tpA, transposeA, tpB, transposeB, tpC, haveMultiplyDoFillComplete, label, params);
495 }
else if (helpers::isTpetraBlockCrs(A) && helpers::isTpetraBlockCrs(B)) {
499 if (!A.
getRowMap()->getComm()->getRank())
500 std::cout <<
"WARNING: Using inefficient BlockCrs Multiply Placeholder" << std::endl;
504 using CRS = Tpetra::CrsMatrix<SC, LO, GO, NO>;
505 RCP<const CRS> Acrs = Tpetra::convertToCrsMatrix(tpA);
506 RCP<const CRS> Bcrs = Tpetra::convertToCrsMatrix(tpB);
509 RCP<ParameterList> new_params;
510 if (!params.is_null()) {
511 new_params = rcp(
new Teuchos::ParameterList(*params));
512 new_params->set(
"compute global constants",
true);
516 RCP<CRS> tempAc = Teuchos::rcp(
new CRS(Acrs->getRowMap(), 0));
517 Tpetra::MatrixMatrix::Multiply(*Acrs, transposeA, *Bcrs, transposeB, *tempAc, haveMultiplyDoFillComplete, label, new_params);
520 RCP<Tpetra::BlockCrsMatrix<SC, LO, GO, NO> > Ac_t = Tpetra::convertToBlockCrsMatrix(*tempAc, A.
GetStorageBlockSize());
522 RCP<Xpetra::CrsMatrix<SC, LO, GO, NO> > Ac_p = Ac_x;
529 TEUCHOS_TEST_FOR_EXCEPTION(1,
Exceptions::RuntimeError,
"Mix-and-match Crs/BlockCrs Multiply not currently supported");
536 if (call_FillComplete_on_result && !haveMultiplyDoFillComplete) {
537 RCP<Teuchos::ParameterList> fillParams = rcp(
new Teuchos::ParameterList());
538 fillParams->set(
"Optimize Storage", doOptimizeStorage);
545 RCP<Matrix> rcpA = Teuchos::rcp_const_cast<
Matrix>(Teuchos::rcpFromRef(A));
546 RCP<Matrix> rcpB = Teuchos::rcp_const_cast<
Matrix>(Teuchos::rcpFromRef(B));
547 C.
CreateView(
"stridedMaps", rcpA, transposeA, rcpB, transposeB);
572 static RCP<Matrix>
Multiply(
const Matrix& A,
bool transposeA,
const Matrix& B,
bool transposeB, RCP<Matrix> C_in,
573 Teuchos::FancyOStream& fos,
574 bool doFillComplete =
true,
575 bool doOptimizeStorage =
true,
576 const std::string& label = std::string(),
577 const RCP<ParameterList>& params = null) {
582 RCP<Matrix> C = C_in;
584 if (C == Teuchos::null) {
585 double nnzPerRow = Teuchos::as<double>(0);
594 nnzPerRow *= nnzPerRow;
597 if (totalNnz < minNnz)
601 fos <<
"Matrix product nnz per row estimate = " << Teuchos::as<LO>(nnzPerRow) << std::endl;
611 fos <<
"Reuse C pattern" << std::endl;
614 Multiply(A, transposeA, B, transposeB, *C, doFillComplete, doOptimizeStorage, label, params);
629 static RCP<Matrix>
Multiply(
const Matrix& A,
bool transposeA,
const Matrix& B,
bool transposeB, Teuchos::FancyOStream& fos,
630 bool callFillCompleteOnResult =
true,
bool doOptimizeStorage =
true,
const std::string& label = std::string(),
631 const RCP<ParameterList>& params = null) {
632 return Multiply(A, transposeA, B, transposeB, Teuchos::null, fos, callFillCompleteOnResult, doOptimizeStorage, label, params);
635 #ifdef HAVE_XPETRA_EPETRAEXT
638 const Epetra_CrsMatrix& epB,
639 Teuchos::FancyOStream& fos) {
640 throw(
Xpetra::Exceptions::RuntimeError(
"MLTwoMatrixMultiply only available for GO=int or GO=long long with EpetraNode (Serial or OpenMP depending on configuration)"));
641 TEUCHOS_UNREACHABLE_RETURN(Teuchos::null);
643 #endif // ifdef HAVE_XPETRA_EPETRAEXT
657 Teuchos::FancyOStream& fos,
658 bool doFillComplete =
true,
659 bool doOptimizeStorage =
true) {
661 "TwoMatrixMultiply for BlockedCrsMatrix not implemented for transposeA==true or transposeB==true");
670 RCP<BlockedCrsMatrix> C = rcp(
new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 ));
672 for (
size_t i = 0; i < A.
Rows(); ++i) {
673 for (
size_t j = 0; j < B.
Cols(); ++j) {
676 for (
size_t l = 0; l < B.
Rows(); ++l) {
680 if (crmat1.is_null() || crmat2.is_null())
688 if (unwrap1.is_null() != unwrap2.is_null()) {
689 if (unwrap1 != Teuchos::null && unwrap1->Rows() == 1 && unwrap1->Cols() == 1)
691 if (unwrap2 != Teuchos::null && unwrap2->Rows() == 1 && unwrap2->Cols() == 1)
692 crmat2 = unwrap2->getCrsMatrix();
696 RCP<CrsMatrixWrap> crop1 = Teuchos::rcp_dynamic_cast<
CrsMatrixWrap>(crmat1);
697 RCP<CrsMatrixWrap> crop2 = Teuchos::rcp_dynamic_cast<
CrsMatrixWrap>(crmat2);
699 "A and B must be either both (compatible) BlockedCrsMatrix objects or both CrsMatrixWrap objects.");
702 if (!crop1.is_null())
703 Teuchos::rcp_const_cast<CrsGraph>(crmat1->getCrsGraph())->computeGlobalConstants();
704 if (!crop2.is_null())
705 Teuchos::rcp_const_cast<CrsGraph>(crmat2->getCrsGraph())->computeGlobalConstants();
708 "crmat1 does not have global constants");
710 "crmat2 does not have global constants");
712 if (crmat1->getGlobalNumEntries() == 0 || crmat2->getGlobalNumEntries() == 0)
716 RCP<Matrix> temp = Teuchos::null;
718 if (crop1 != Teuchos::null && crop2 != Teuchos::null)
719 temp =
Multiply(*crop1,
false, *crop2,
false, fos);
721 RCP<BlockedCrsMatrix> bop1 = Teuchos::rcp_dynamic_cast<
BlockedCrsMatrix>(crmat1);
722 RCP<BlockedCrsMatrix> bop2 = Teuchos::rcp_dynamic_cast<
BlockedCrsMatrix>(crmat2);
723 TEUCHOS_TEST_FOR_EXCEPTION(bop1.is_null() ==
true,
Xpetra::Exceptions::BadCast,
"A is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
724 TEUCHOS_TEST_FOR_EXCEPTION(bop2.is_null() ==
true,
Xpetra::Exceptions::BadCast,
"B is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
725 TEUCHOS_TEST_FOR_EXCEPTION(bop1->Cols() != bop2->Rows(),
Xpetra::Exceptions::RuntimeError,
"A has " << bop1->Cols() <<
" columns and B has " << bop2->Rows() <<
" rows. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
726 TEUCHOS_TEST_FOR_EXCEPTION(bop1->getDomainMap()->isSameAs(*(bop2->getRangeMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Domain map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
729 temp =
TwoMatrixMultiplyBlock(*bop1, transposeA, *bop2, transposeB, fos, doFillComplete, doOptimizeStorage);
731 RCP<BlockedCrsMatrix> btemp = Teuchos::rcp_dynamic_cast<
BlockedCrsMatrix>(temp);
732 TEUCHOS_TEST_FOR_EXCEPTION(btemp->Rows() != bop1->Rows(),
Xpetra::Exceptions::RuntimeError,
"Number of block rows of local blocked operator is " << btemp->Rows() <<
" but should be " << bop1->Rows() <<
". (TwoMatrixMultiplyBlock)");
733 TEUCHOS_TEST_FOR_EXCEPTION(btemp->Cols() != bop2->Cols(),
Xpetra::Exceptions::RuntimeError,
"Number of block cols of local blocked operator is " << btemp->Cols() <<
" but should be " << bop2->Cols() <<
". (TwoMatrixMultiplyBlock)");
734 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getFullMap()->isSameAs(*(bop1->getRangeMapExtractor()->getFullMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Range map of local blocked operator should be same as first operator. (TwoMatrixMultiplyBlock)");
735 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getFullMap()->isSameAs(*(bop2->getDomainMapExtractor()->getFullMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Domain map of local blocked operator should be same as second operator. (TwoMatrixMultiplyBlock)");
736 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getThyraMode() != bop1->getRangeMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Thyra mode of local range map extractor incompatible with range map extractor of A (TwoMatrixMultiplyBlock)");
737 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getThyraMode() != bop2->getDomainMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Thyra mode of local domain map extractor incompatible with domain map extractor of B (TwoMatrixMultiplyBlock)");
742 RCP<Matrix> addRes = null;
751 if (!Cij.is_null()) {
752 if (Cij->isFillComplete())
755 C->setMatrix(i, j, Cij);
757 C->setMatrix(i, j, Teuchos::null);
785 throw Exceptions::RuntimeError(
"TwoMatrixAdd for Epetra matrices needs <double,int,int> for Scalar, LocalOrdinal and GlobalOrdinal.");
787 #ifdef HAVE_XPETRA_TPETRA
791 Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, beta);
813 const Matrix& B,
bool transposeB,
const SC& beta,
814 RCP<Matrix>& C, Teuchos::FancyOStream& fos,
bool AHasFixedNnzPerRow =
false) {
815 RCP<const Matrix> rcpA = Teuchos::rcpFromRef(A);
816 RCP<const Matrix> rcpB = Teuchos::rcpFromRef(B);
817 RCP<const BlockedCrsMatrix> rcpBopA = Teuchos::rcp_dynamic_cast<
const BlockedCrsMatrix>(rcpA);
818 RCP<const BlockedCrsMatrix> rcpBopB = Teuchos::rcp_dynamic_cast<
const BlockedCrsMatrix>(rcpB);
826 if (rcpBopA == Teuchos::null && rcpBopB == Teuchos::null) {
832 #ifdef HAVE_XPETRA_TPETRA
833 using tcrs_matrix_type = Tpetra::CrsMatrix<SC, LO, GO, NO>;
835 const tcrs_matrix_type& tpA = helpers::Op2TpetraCrs(A);
836 const tcrs_matrix_type& tpB = helpers::Op2TpetraCrs(B);
837 C = helpers::tpetraAdd(tpA, transposeA, alpha, tpB, transposeB, beta);
843 if (A.
IsView(
"stridedMaps")) C->CreateView(
"stridedMaps", rcpFromRef(A));
844 if (B.
IsView(
"stridedMaps")) C->CreateView(
"stridedMaps", rcpFromRef(B));
848 else if (rcpBopA == Teuchos::null && rcpBopB != Teuchos::null) {
849 RCP<const MapExtractor> rgmapextractor = rcpBopB->getRangeMapExtractor();
850 RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
856 for (
size_t j = 0; j < rcpBopB->Cols(); ++j) {
857 RCP<Matrix> Cij = Teuchos::null;
858 if (rcpA != Teuchos::null &&
859 rcpBopB->getMatrix(i, j) != Teuchos::null) {
862 *(rcpBopB->getMatrix(i, j)), transposeB, beta,
863 Cij, fos, AHasFixedNnzPerRow);
864 }
else if (rcpA == Teuchos::null &&
865 rcpBopB->getMatrix(i, j) != Teuchos::null) {
866 Cij = rcpBopB->getMatrix(i, j);
867 }
else if (rcpA != Teuchos::null &&
868 rcpBopB->getMatrix(i, j) == Teuchos::null) {
869 Cij = Teuchos::rcp_const_cast<
Matrix>(rcpA);
874 if (!Cij.is_null()) {
875 if (Cij->isFillComplete())
878 bC->setMatrix(i, j, Cij);
880 bC->setMatrix(i, j, Teuchos::null);
885 else if (rcpBopA != Teuchos::null && rcpBopB == Teuchos::null) {
886 RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
887 RCP<const MapExtractor> domapextractor = rcpBopA->getDomainMapExtractor();
892 for (
size_t i = 0; i < rcpBopA->Rows(); ++i) {
893 RCP<Matrix> Cij = Teuchos::null;
894 if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
895 rcpB != Teuchos::null) {
897 TwoMatrixAdd(*(rcpBopA->getMatrix(i, j)), transposeA, alpha,
898 *rcpB, transposeB, beta,
899 Cij, fos, AHasFixedNnzPerRow);
900 }
else if (rcpBopA->getMatrix(i, j) == Teuchos::null &&
901 rcpB != Teuchos::null) {
902 Cij = Teuchos::rcp_const_cast<
Matrix>(rcpB);
903 }
else if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
904 rcpB == Teuchos::null) {
905 Cij = rcpBopA->getMatrix(i, j);
910 if (!Cij.is_null()) {
911 if (Cij->isFillComplete())
914 bC->setMatrix(i, j, Cij);
916 bC->setMatrix(i, j, Teuchos::null);
925 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows() != rcpBopB->Rows(),
Xpetra::Exceptions::RuntimeError,
"A has " << rcpBopA->Rows() <<
" rows and B has " << rcpBopA->Rows() <<
" rows. Matrices are not compatible! (TwoMatrixAdd)");
926 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows() != rcpBopB->Rows(),
Xpetra::Exceptions::RuntimeError,
"A has " << rcpBopA->Cols() <<
" cols and B has " << rcpBopA->Cols() <<
" cols. Matrices are not compatible! (TwoMatrixAdd)");
927 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMap()->isSameAs(*(rcpBopB->getRangeMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Range map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixAdd)");
928 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMap()->isSameAs(*(rcpBopB->getDomainMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Domain map of A is not the same as domain map of B. Matrices are not compatible! (TwoMatrixAdd)");
929 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMapExtractor()->getThyraMode() != rcpBopB->getRangeMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Different Thyra/Xpetra style gids in RangeMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
930 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMapExtractor()->getThyraMode() != rcpBopB->getDomainMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Different Thyra/Xpetra style gids in DomainMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
932 RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
933 RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
937 for (
size_t i = 0; i < rcpBopA->Rows(); ++i) {
938 for (
size_t j = 0; j < rcpBopB->Cols(); ++j) {
940 RCP<Matrix> Cij = Teuchos::null;
941 if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
942 rcpBopB->getMatrix(i, j) != Teuchos::null) {
944 TwoMatrixAdd(*(rcpBopA->getMatrix(i, j)), transposeA, alpha,
945 *(rcpBopB->getMatrix(i, j)), transposeB, beta,
946 Cij, fos, AHasFixedNnzPerRow);
947 }
else if (rcpBopA->getMatrix(i, j) == Teuchos::null &&
948 rcpBopB->getMatrix(i, j) != Teuchos::null) {
949 Cij = rcpBopB->getMatrix(i, j);
950 }
else if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
951 rcpBopB->getMatrix(i, j) == Teuchos::null) {
952 Cij = rcpBopA->getMatrix(i, j);
957 if (!Cij.is_null()) {
958 if (Cij->isFillComplete())
961 bC->setMatrix(i, j, Cij);
963 bC->setMatrix(i, j, Teuchos::null);
973 #ifdef HAVE_XPETRA_EPETRA
1009 const Matrix& B,
bool transposeB,
1011 bool call_FillComplete_on_result =
true,
1012 bool doOptimizeStorage =
true,
1013 const std::string& label = std::string(),
1014 const RCP<ParameterList>& params = null) {
1015 TEUCHOS_TEST_FOR_EXCEPTION(transposeA ==
false && C.
getRowMap()->isSameAs(*A.
getRowMap()) ==
false,
1017 TEUCHOS_TEST_FOR_EXCEPTION(transposeA ==
true && C.
getRowMap()->isSameAs(*A.
getDomainMap()) ==
false,
1023 bool haveMultiplyDoFillComplete = call_FillComplete_on_result && doOptimizeStorage;
1028 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1029 helpers::epetraExtMult(A, transposeA, B, transposeB, C, haveMultiplyDoFillComplete);
1034 #ifdef HAVE_XPETRA_TPETRA
1035 #if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_INT))) || \
1036 (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_INT))))
1039 if (helpers::isTpetraCrs(A) && helpers::isTpetraCrs(B) && helpers::isTpetraCrs(C)) {
1041 const Tpetra::CrsMatrix<SC, LO, GO, NO>& tpA = helpers::Op2TpetraCrs(A);
1042 const Tpetra::CrsMatrix<SC, LO, GO, NO>& tpB = helpers::Op2TpetraCrs(B);
1043 Tpetra::CrsMatrix<SC, LO, GO, NO>& tpC = helpers::Op2NonConstTpetraCrs(C);
1047 Tpetra::MatrixMatrix::Multiply(tpA, transposeA, tpB, transposeB, tpC, haveMultiplyDoFillComplete, label, params);
1048 }
else if (helpers::isTpetraBlockCrs(A) && helpers::isTpetraBlockCrs(B)) {
1053 if (!A.
getRowMap()->getComm()->getRank())
1054 std::cout <<
"WARNING: Using inefficient BlockCrs Multiply Placeholder" << std::endl;
1058 using CRS = Tpetra::CrsMatrix<SC, LO, GO, NO>;
1059 RCP<const CRS> Acrs = Tpetra::convertToCrsMatrix(tpA);
1060 RCP<const CRS> Bcrs = Tpetra::convertToCrsMatrix(tpB);
1063 RCP<ParameterList> new_params;
1064 if (!params.is_null()) {
1065 new_params = rcp(
new Teuchos::ParameterList(*params));
1066 new_params->set(
"compute global constants",
true);
1070 RCP<CRS> tempAc = Teuchos::rcp(
new CRS(Acrs->getRowMap(), 0));
1071 Tpetra::MatrixMatrix::Multiply(*Acrs, transposeA, *Bcrs, transposeB, *tempAc, haveMultiplyDoFillComplete, label, new_params);
1074 RCP<Tpetra::BlockCrsMatrix<SC, LO, GO, NO> > Ac_t = Tpetra::convertToBlockCrsMatrix(*tempAc, A.
GetStorageBlockSize());
1076 RCP<Xpetra::CrsMatrix<SC, LO, GO, NO> > Ac_p = Ac_x;
1083 TEUCHOS_TEST_FOR_EXCEPTION(1,
Exceptions::RuntimeError,
"Mix-and-match Crs/BlockCrs Multiply not currently supported");
1091 if (call_FillComplete_on_result && !haveMultiplyDoFillComplete) {
1092 RCP<Teuchos::ParameterList> fillParams = rcp(
new Teuchos::ParameterList());
1093 fillParams->set(
"Optimize Storage", doOptimizeStorage);
1100 RCP<Matrix> rcpA = Teuchos::rcp_const_cast<
Matrix>(Teuchos::rcpFromRef(A));
1101 RCP<Matrix> rcpB = Teuchos::rcp_const_cast<
Matrix>(Teuchos::rcpFromRef(B));
1102 C.
CreateView(
"stridedMaps", rcpA, transposeA, rcpB, transposeB);
1128 const Matrix& B,
bool transposeB,
1130 Teuchos::FancyOStream& fos,
1131 bool doFillComplete =
true,
1132 bool doOptimizeStorage =
true,
1133 const std::string& label = std::string(),
1134 const RCP<ParameterList>& params = null) {
1140 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT) && defined(HAVE_XPETRA_ML_MMM)
1146 RCP<Matrix> C = Convert_Epetra_CrsMatrix_ToXpetra_CrsMatrixWrap<SC, LO, GO, NO>(epC);
1147 if (doFillComplete) {
1148 RCP<Teuchos::ParameterList> fillParams = rcp(
new Teuchos::ParameterList());
1149 fillParams->set(
"Optimize Storage", doOptimizeStorage);
1156 C->CreateView(
"stridedMaps", rcpFromRef(A), transposeA, rcpFromRef(B), transposeB);
1160 #endif // EPETRA + EPETRAEXT + ML
1163 RCP<Matrix> C = C_in;
1165 if (C == Teuchos::null) {
1166 double nnzPerRow = Teuchos::as<double>(0);
1175 nnzPerRow *= nnzPerRow;
1178 if (totalNnz < minNnz)
1182 fos <<
"Matrix product nnz per row estimate = " << Teuchos::as<LO>(nnzPerRow) << std::endl;
1193 fos <<
"Reuse C pattern" << std::endl;
1196 Multiply(A, transposeA, B, transposeB, *C, doFillComplete, doOptimizeStorage, label, params);
1212 const Matrix& B,
bool transposeB,
1213 Teuchos::FancyOStream& fos,
1214 bool callFillCompleteOnResult =
true,
1215 bool doOptimizeStorage =
true,
1216 const std::string& label = std::string(),
1217 const RCP<ParameterList>& params = null) {
1218 return Multiply(A, transposeA, B, transposeB, Teuchos::null, fos, callFillCompleteOnResult, doOptimizeStorage, label, params);
1221 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1224 const Epetra_CrsMatrix& epB,
1225 Teuchos::FancyOStream& fos) {
1226 #if defined(HAVE_XPETRA_ML_MMM) // Note: this is currently not supported
1228 ML_Comm_Create(&comm);
1229 fos <<
"****** USING ML's MATRIX MATRIX MULTIPLY ******" << std::endl;
1232 const Epetra_MpiComm* Mcomm =
dynamic_cast<const Epetra_MpiComm*
>(&(epA.Comm()));
1234 ML_Comm_Set_UsrComm(comm, Mcomm->GetMpiComm());
1237 EpetraExt::CrsMatrix_SolverMap Atransform;
1238 EpetraExt::CrsMatrix_SolverMap Btransform;
1239 const Epetra_CrsMatrix& A = Atransform(const_cast<Epetra_CrsMatrix&>(epA));
1240 const Epetra_CrsMatrix& B = Btransform(const_cast<Epetra_CrsMatrix&>(epB));
1246 ML_Operator* ml_As = ML_Operator_Create(comm);
1247 ML_Operator* ml_Bs = ML_Operator_Create(comm);
1248 ML_Operator_WrapEpetraCrsMatrix(const_cast<Epetra_CrsMatrix*>(&A), ml_As);
1249 ML_Operator_WrapEpetraCrsMatrix(const_cast<Epetra_CrsMatrix*>(&B), ml_Bs);
1250 ML_Operator* ml_AtimesB = ML_Operator_Create(comm);
1252 Teuchos::TimeMonitor tm(*Teuchos::TimeMonitor::getNewTimer(
"ML_2matmult kernel"));
1253 ML_2matmult(ml_As, ml_Bs, ml_AtimesB, ML_CSR_MATRIX);
1255 ML_Operator_Destroy(&ml_As);
1256 ML_Operator_Destroy(&ml_Bs);
1261 int N_local = ml_AtimesB->invec_leng;
1262 ML_CommInfoOP* getrow_comm = ml_AtimesB->getrow->pre_comm;
1264 ML_Comm* comm_AB = ml_AtimesB->comm;
1265 if (N_local != B.DomainMap().NumMyElements())
1270 for (
int i = 0; i < getrow_comm->N_neighbors; i++) {
1271 N_rcvd += (getrow_comm->neighbors)[i].N_rcv;
1272 N_send += (getrow_comm->neighbors)[i].N_send;
1273 if (((getrow_comm->neighbors)[i].N_rcv != 0) &&
1274 ((getrow_comm->neighbors)[i].rcv_list != NULL)) flag = 1;
1278 std::vector<double> dtemp(N_local + N_rcvd + 1);
1279 std::vector<int> cmap(N_local + N_rcvd + 1);
1280 for (
int i = 0; i < N_local; ++i) {
1281 cmap[i] = B.DomainMap().GID(i);
1282 dtemp[i] = (double)cmap[i];
1284 ML_cheap_exchange_bdry(&dtemp[0], getrow_comm, N_local, N_send, comm_AB);
1286 int count = N_local;
1287 const int neighbors = getrow_comm->N_neighbors;
1288 for (
int i = 0; i < neighbors; i++) {
1289 const int nrcv = getrow_comm->neighbors[i].N_rcv;
1290 for (
int j = 0; j < nrcv; j++)
1291 cmap[getrow_comm->neighbors[i].rcv_list[j]] = (
int)dtemp[count++];
1294 for (
int i = 0; i < N_local + N_rcvd; ++i)
1295 cmap[i] = (
int)dtemp[i];
1300 Epetra_Map gcmap(-1, N_local + N_rcvd, &cmap[0], B.ColMap().IndexBase(), A.Comm());
1307 const int myrowlength = A.RowMap().NumMyElements();
1308 const Epetra_Map& rowmap = A.RowMap();
1313 int educatedguess = 0;
1314 for (
int i = 0; i < myrowlength; ++i) {
1316 ML_get_matrix_row(ml_AtimesB, 1, &i, &allocated, &bindx, &val, &rowlength, 0);
1317 if (rowlength > educatedguess)
1318 educatedguess = rowlength;
1322 RCP<Epetra_CrsMatrix> result = rcp(
new Epetra_CrsMatrix(::Copy, A.RangeMap(), gcmap, educatedguess,
false));
1324 std::vector<int> gcid(educatedguess);
1325 for (
int i = 0; i < myrowlength; ++i) {
1326 const int grid = rowmap.GID(i);
1328 ML_get_matrix_row(ml_AtimesB, 1, &i, &allocated, &bindx, &val, &rowlength, 0);
1329 if (!rowlength)
continue;
1330 if ((
int)gcid.size() < rowlength) gcid.resize(rowlength);
1331 for (
int j = 0; j < rowlength; ++j) {
1332 gcid[j] = gcmap.GID(bindx[j]);
1336 int err = result->InsertGlobalValues(grid, rowlength, val, &gcid[0]);
1337 if (err != 0 && err != 1) {
1338 std::ostringstream errStr;
1339 errStr <<
"Epetra_CrsMatrix::InsertGlobalValues returned err=" << err;
1344 if (bindx) ML_free(bindx);
1345 if (val) ML_free(val);
1346 ML_Operator_Destroy(&ml_AtimesB);
1347 ML_Comm_Destroy(&comm);
1350 #else // no MUELU_ML
1355 "No ML multiplication available. This feature is currently not supported by Xpetra.");
1356 TEUCHOS_UNREACHABLE_RETURN(Teuchos::null);
1359 #endif // ifdef HAVE_XPETRA_EPETRAEXT
1373 Teuchos::FancyOStream& fos,
1374 bool doFillComplete =
true,
1375 bool doOptimizeStorage =
true) {
1377 "TwoMatrixMultiply for BlockedCrsMatrix not implemented for transposeA==true or transposeB==true");
1386 RCP<BlockedCrsMatrix> C = rcp(
new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 ));
1388 for (
size_t i = 0; i < A.
Rows(); ++i) {
1389 for (
size_t j = 0; j < B.
Cols(); ++j) {
1392 for (
size_t l = 0; l < B.
Rows(); ++l) {
1396 if (crmat1.is_null() || crmat2.is_null())
1404 if (unwrap1.is_null() != unwrap2.is_null()) {
1405 if (unwrap1 != Teuchos::null && unwrap1->Rows() == 1 && unwrap1->Cols() == 1)
1407 if (unwrap2 != Teuchos::null && unwrap2->Rows() == 1 && unwrap2->Cols() == 1)
1408 crmat2 = unwrap2->getCrsMatrix();
1412 RCP<CrsMatrixWrap> crop1 = Teuchos::rcp_dynamic_cast<
CrsMatrixWrap>(crmat1);
1413 RCP<CrsMatrixWrap> crop2 = Teuchos::rcp_dynamic_cast<
CrsMatrixWrap>(crmat2);
1415 "A and B must be either both (compatible) BlockedCrsMatrix objects or both CrsMatrixWrap objects.");
1418 if (!crop1.is_null())
1419 Teuchos::rcp_const_cast<CrsGraph>(crmat1->getCrsGraph())->computeGlobalConstants();
1420 if (!crop2.is_null())
1421 Teuchos::rcp_const_cast<CrsGraph>(crmat2->getCrsGraph())->computeGlobalConstants();
1424 "crmat1 does not have global constants");
1426 "crmat2 does not have global constants");
1428 if (crmat1->getGlobalNumEntries() == 0 || crmat2->getGlobalNumEntries() == 0)
1432 RCP<Matrix> temp = Teuchos::null;
1434 if (crop1 != Teuchos::null && crop2 != Teuchos::null)
1435 temp =
Multiply(*crop1,
false, *crop2,
false, fos);
1437 RCP<BlockedCrsMatrix> bop1 = Teuchos::rcp_dynamic_cast<
BlockedCrsMatrix>(crmat1);
1438 RCP<BlockedCrsMatrix> bop2 = Teuchos::rcp_dynamic_cast<
BlockedCrsMatrix>(crmat2);
1439 TEUCHOS_TEST_FOR_EXCEPTION(bop1.is_null() ==
true,
Xpetra::Exceptions::BadCast,
"A is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
1440 TEUCHOS_TEST_FOR_EXCEPTION(bop2.is_null() ==
true,
Xpetra::Exceptions::BadCast,
"B is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
1441 TEUCHOS_TEST_FOR_EXCEPTION(bop1->Cols() != bop2->Rows(),
Xpetra::Exceptions::RuntimeError,
"A has " << bop1->Cols() <<
" columns and B has " << bop2->Rows() <<
" rows. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
1442 TEUCHOS_TEST_FOR_EXCEPTION(bop1->getDomainMap()->isSameAs(*(bop2->getRangeMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Domain map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
1445 temp =
TwoMatrixMultiplyBlock(*bop1, transposeA, *bop2, transposeB, fos, doFillComplete, doOptimizeStorage);
1447 RCP<BlockedCrsMatrix> btemp = Teuchos::rcp_dynamic_cast<
BlockedCrsMatrix>(temp);
1448 TEUCHOS_TEST_FOR_EXCEPTION(btemp->Rows() != bop1->Rows(),
Xpetra::Exceptions::RuntimeError,
"Number of block rows of local blocked operator is " << btemp->Rows() <<
" but should be " << bop1->Rows() <<
". (TwoMatrixMultiplyBlock)");
1449 TEUCHOS_TEST_FOR_EXCEPTION(btemp->Cols() != bop2->Cols(),
Xpetra::Exceptions::RuntimeError,
"Number of block cols of local blocked operator is " << btemp->Cols() <<
" but should be " << bop2->Cols() <<
". (TwoMatrixMultiplyBlock)");
1450 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getFullMap()->isSameAs(*(bop1->getRangeMapExtractor()->getFullMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Range map of local blocked operator should be same as first operator. (TwoMatrixMultiplyBlock)");
1451 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getFullMap()->isSameAs(*(bop2->getDomainMapExtractor()->getFullMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Domain map of local blocked operator should be same as second operator. (TwoMatrixMultiplyBlock)");
1452 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getThyraMode() != bop1->getRangeMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Thyra mode of local range map extractor incompatible with range map extractor of A (TwoMatrixMultiplyBlock)");
1453 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getThyraMode() != bop2->getDomainMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Thyra mode of local domain map extractor incompatible with domain map extractor of B (TwoMatrixMultiplyBlock)");
1458 RCP<Matrix> addRes = null;
1467 if (!Cij.is_null()) {
1468 if (Cij->isFillComplete())
1471 C->setMatrix(i, j, Cij);
1473 C->setMatrix(i, j, Teuchos::null);
1498 "TwoMatrixAdd: matrix row maps are not the same.");
1501 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1506 int rv = EpetraExt::MatrixMatrix::Add(epA, transposeA, alpha, epB, beta);
1510 std::ostringstream buf;
1515 #ifdef HAVE_XPETRA_TPETRA
1516 #if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_INT))) || \
1517 (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_INT))))
1523 Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, beta);
1546 const Matrix& B,
bool transposeB,
const SC& beta,
1547 RCP<Matrix>& C, Teuchos::FancyOStream& fos,
bool AHasFixedNnzPerRow =
false) {
1549 RCP<const Matrix> rcpA = Teuchos::rcpFromRef(A);
1550 RCP<const Matrix> rcpB = Teuchos::rcpFromRef(B);
1551 RCP<const BlockedCrsMatrix> rcpBopA = Teuchos::rcp_dynamic_cast<
const BlockedCrsMatrix>(rcpA);
1552 RCP<const BlockedCrsMatrix> rcpBopB = Teuchos::rcp_dynamic_cast<
const BlockedCrsMatrix>(rcpB);
1554 if (rcpBopA == Teuchos::null && rcpBopB == Teuchos::null) {
1560 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1561 const Epetra_CrsMatrix& epA = helpers::Op2EpetraCrs(A);
1562 const Epetra_CrsMatrix& epB = helpers::Op2EpetraCrs(B);
1564 size_t maxNzInA = 0;
1565 size_t maxNzInB = 0;
1566 size_t numLocalRows = 0;
1573 if (maxNzInA == 1 || maxNzInB == 1 || AHasFixedNnzPerRow) {
1576 Teuchos::ArrayRCP<size_t> exactNnzPerRow(numLocalRows);
1578 if ((maxNzInA == 1 && maxNzInB > 1) || AHasFixedNnzPerRow) {
1579 for (
size_t i = 0; i < numLocalRows; ++i)
1583 for (
size_t i = 0; i < numLocalRows; ++i)
1587 fos <<
"MatrixMatrix::TwoMatrixAdd : special case detected (one matrix has a fixed nnz per row)"
1588 <<
", using static profiling" << std::endl;
1597 fos <<
"MatrixMatrix::TwoMatrixAdd : ** WARNING ** estimate could be badly wrong because second summand is transposed" << std::endl;
1599 RCP<Epetra_CrsMatrix> epC = helpers::Op2NonConstEpetraCrs(C);
1600 Epetra_CrsMatrix* ref2epC = &*epC;
1603 int rv = EpetraExt::MatrixMatrix::Add(epA, transposeA, alpha, epB, transposeB, beta, ref2epC);
1611 #ifdef HAVE_XPETRA_TPETRA
1612 #if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_INT))) || \
1613 (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_INT))))
1616 using tcrs_matrix_type = Tpetra::CrsMatrix<SC, LO, GO, NO>;
1617 const tcrs_matrix_type& tpA = helpers::Op2TpetraCrs(A);
1618 const tcrs_matrix_type& tpB = helpers::Op2TpetraCrs(B);
1619 C = helpers::tpetraAdd(tpA, transposeA, alpha, tpB, transposeB, beta);
1627 if (A.
IsView(
"stridedMaps")) C->CreateView(
"stridedMaps", rcpFromRef(A));
1628 if (B.
IsView(
"stridedMaps")) C->CreateView(
"stridedMaps", rcpFromRef(B));
1632 else if (rcpBopA == Teuchos::null && rcpBopB != Teuchos::null) {
1633 RCP<const MapExtractor> rgmapextractor = rcpBopB->getRangeMapExtractor();
1634 RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
1640 for (
size_t j = 0; j < rcpBopB->Cols(); ++j) {
1641 RCP<Matrix> Cij = Teuchos::null;
1642 if (rcpA != Teuchos::null &&
1643 rcpBopB->getMatrix(i, j) != Teuchos::null) {
1646 *(rcpBopB->getMatrix(i, j)), transposeB, beta,
1647 Cij, fos, AHasFixedNnzPerRow);
1648 }
else if (rcpA == Teuchos::null &&
1649 rcpBopB->getMatrix(i, j) != Teuchos::null) {
1650 Cij = rcpBopB->getMatrix(i, j);
1651 }
else if (rcpA != Teuchos::null &&
1652 rcpBopB->getMatrix(i, j) == Teuchos::null) {
1653 Cij = Teuchos::rcp_const_cast<
Matrix>(rcpA);
1655 Cij = Teuchos::null;
1658 if (!Cij.is_null()) {
1659 if (Cij->isFillComplete())
1661 Cij->fillComplete();
1662 bC->setMatrix(i, j, Cij);
1664 bC->setMatrix(i, j, Teuchos::null);
1669 else if (rcpBopA != Teuchos::null && rcpBopB == Teuchos::null) {
1670 RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
1671 RCP<const MapExtractor> domapextractor = rcpBopA->getDomainMapExtractor();
1677 for (
size_t i = 0; i < rcpBopA->Rows(); ++i) {
1678 RCP<Matrix> Cij = Teuchos::null;
1679 if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
1680 rcpB != Teuchos::null) {
1682 TwoMatrixAdd(*(rcpBopA->getMatrix(i, j)), transposeA, alpha,
1683 *rcpB, transposeB, beta,
1684 Cij, fos, AHasFixedNnzPerRow);
1685 }
else if (rcpBopA->getMatrix(i, j) == Teuchos::null &&
1686 rcpB != Teuchos::null) {
1687 Cij = Teuchos::rcp_const_cast<
Matrix>(rcpB);
1688 }
else if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
1689 rcpB == Teuchos::null) {
1690 Cij = rcpBopA->getMatrix(i, j);
1692 Cij = Teuchos::null;
1695 if (!Cij.is_null()) {
1696 if (Cij->isFillComplete())
1698 Cij->fillComplete();
1699 bC->setMatrix(i, j, Cij);
1701 bC->setMatrix(i, j, Teuchos::null);
1708 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA.is_null() ==
true,
Xpetra::Exceptions::BadCast,
"A is not a BlockedCrsMatrix. (TwoMatrixAdd)");
1709 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopB.is_null() ==
true,
Xpetra::Exceptions::BadCast,
"B is not a BlockedCrsMatrix. (TwoMatrixAdd)");
1710 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows() != rcpBopB->Rows(),
Xpetra::Exceptions::RuntimeError,
"A has " << rcpBopA->Rows() <<
" rows and B has " << rcpBopA->Rows() <<
" rows. Matrices are not compatible! (TwoMatrixAdd)");
1711 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows() != rcpBopB->Rows(),
Xpetra::Exceptions::RuntimeError,
"A has " << rcpBopA->Cols() <<
" cols and B has " << rcpBopA->Cols() <<
" cols. Matrices are not compatible! (TwoMatrixAdd)");
1712 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMap()->isSameAs(*(rcpBopB->getRangeMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Range map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixAdd)");
1713 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMap()->isSameAs(*(rcpBopB->getDomainMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Domain map of A is not the same as domain map of B. Matrices are not compatible! (TwoMatrixAdd)");
1714 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMapExtractor()->getThyraMode() != rcpBopB->getRangeMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Different Thyra/Xpetra style gids in RangeMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
1715 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMapExtractor()->getThyraMode() != rcpBopB->getDomainMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Different Thyra/Xpetra style gids in DomainMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
1717 RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
1718 RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
1723 for (
size_t i = 0; i < rcpBopA->Rows(); ++i) {
1724 for (
size_t j = 0; j < rcpBopB->Cols(); ++j) {
1726 RCP<Matrix> Cij = Teuchos::null;
1727 if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
1728 rcpBopB->getMatrix(i, j) != Teuchos::null) {
1731 TwoMatrixAdd(*(rcpBopA->getMatrix(i, j)), transposeA, alpha,
1732 *(rcpBopB->getMatrix(i, j)), transposeB, beta,
1733 Cij, fos, AHasFixedNnzPerRow);
1734 }
else if (rcpBopA->getMatrix(i, j) == Teuchos::null &&
1735 rcpBopB->getMatrix(i, j) != Teuchos::null) {
1736 Cij = rcpBopB->getMatrix(i, j);
1737 }
else if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
1738 rcpBopB->getMatrix(i, j) == Teuchos::null) {
1739 Cij = rcpBopA->getMatrix(i, j);
1741 Cij = Teuchos::null;
1744 if (!Cij.is_null()) {
1745 if (Cij->isFillComplete())
1748 Cij->fillComplete();
1749 bC->setMatrix(i, j, Cij);
1751 bC->setMatrix(i, j, Teuchos::null);
1795 const Matrix& B,
bool transposeB,
1797 bool call_FillComplete_on_result =
true,
1798 bool doOptimizeStorage =
true,
1799 const std::string& label = std::string(),
1800 const RCP<ParameterList>& params = null) {
1802 TEUCHOS_TEST_FOR_EXCEPTION(transposeA ==
false && C.
getRowMap()->isSameAs(*A.
getRowMap()) ==
false,
1804 TEUCHOS_TEST_FOR_EXCEPTION(transposeA ==
true && C.
getRowMap()->isSameAs(*A.
getDomainMap()) ==
false,
1810 bool haveMultiplyDoFillComplete = call_FillComplete_on_result && doOptimizeStorage;
1813 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1814 helpers::epetraExtMult(A, transposeA, B, transposeB, C, haveMultiplyDoFillComplete);
1819 #ifdef HAVE_XPETRA_TPETRA
1820 #if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))) || \
1821 (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))))
1824 if (helpers::isTpetraCrs(A) && helpers::isTpetraCrs(B) && helpers::isTpetraCrs(C)) {
1826 const Tpetra::CrsMatrix<SC, LO, GO, NO>& tpA = helpers::Op2TpetraCrs(A);
1827 const Tpetra::CrsMatrix<SC, LO, GO, NO>& tpB = helpers::Op2TpetraCrs(B);
1828 Tpetra::CrsMatrix<SC, LO, GO, NO>& tpC = helpers::Op2NonConstTpetraCrs(C);
1832 Tpetra::MatrixMatrix::Multiply(tpA, transposeA, tpB, transposeB, tpC, haveMultiplyDoFillComplete, label, params);
1833 }
else if (helpers::isTpetraBlockCrs(A) && helpers::isTpetraBlockCrs(B)) {
1838 if (!A.
getRowMap()->getComm()->getRank())
1839 std::cout <<
"WARNING: Using inefficient BlockCrs Multiply Placeholder" << std::endl;
1843 using CRS = Tpetra::CrsMatrix<SC, LO, GO, NO>;
1844 RCP<const CRS> Acrs = Tpetra::convertToCrsMatrix(tpA);
1845 RCP<const CRS> Bcrs = Tpetra::convertToCrsMatrix(tpB);
1848 RCP<ParameterList> new_params;
1849 if (!params.is_null()) {
1850 new_params = rcp(
new Teuchos::ParameterList(*params));
1851 new_params->set(
"compute global constants",
true);
1855 RCP<CRS> tempAc = Teuchos::rcp(
new CRS(Acrs->getRowMap(), 0));
1856 Tpetra::MatrixMatrix::Multiply(*Acrs, transposeA, *Bcrs, transposeB, *tempAc, haveMultiplyDoFillComplete, label, new_params);
1859 RCP<Tpetra::BlockCrsMatrix<SC, LO, GO, NO> > Ac_t = Tpetra::convertToBlockCrsMatrix(*tempAc, A.
GetStorageBlockSize());
1861 RCP<Xpetra::CrsMatrix<SC, LO, GO, NO> > Ac_p = Ac_x;
1868 TEUCHOS_TEST_FOR_EXCEPTION(1,
Exceptions::RuntimeError,
"Mix-and-match Crs/BlockCrs Multiply not currently supported");
1877 if (call_FillComplete_on_result && !haveMultiplyDoFillComplete) {
1878 RCP<Teuchos::ParameterList> fillParams = rcp(
new Teuchos::ParameterList());
1879 fillParams->set(
"Optimize Storage", doOptimizeStorage);
1886 RCP<Matrix> rcpA = Teuchos::rcp_const_cast<
Matrix>(Teuchos::rcpFromRef(A));
1887 RCP<Matrix> rcpB = Teuchos::rcp_const_cast<
Matrix>(Teuchos::rcpFromRef(B));
1888 C.
CreateView(
"stridedMaps", rcpA, transposeA, rcpB, transposeB);
1914 const Matrix& B,
bool transposeB,
1916 Teuchos::FancyOStream& fos,
1917 bool doFillComplete =
true,
1918 bool doOptimizeStorage =
true,
1919 const std::string& label = std::string(),
1920 const RCP<ParameterList>& params = null) {
1925 RCP<Matrix> C = C_in;
1927 if (C == Teuchos::null) {
1928 double nnzPerRow = Teuchos::as<double>(0);
1937 nnzPerRow *= nnzPerRow;
1940 if (totalNnz < minNnz)
1944 fos <<
"Matrix product nnz per row estimate = " << Teuchos::as<LO>(nnzPerRow) << std::endl;
1954 fos <<
"Reuse C pattern" << std::endl;
1957 Multiply(A, transposeA, B, transposeB, *C, doFillComplete, doOptimizeStorage, label, params);
1973 const Matrix& B,
bool transposeB,
1974 Teuchos::FancyOStream& fos,
1975 bool callFillCompleteOnResult =
true,
1976 bool doOptimizeStorage =
true,
1977 const std::string& label = std::string(),
1978 const RCP<ParameterList>& params = null) {
1979 return Multiply(A, transposeA, B, transposeB, Teuchos::null, fos, callFillCompleteOnResult, doOptimizeStorage, label, params);
1982 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1985 const Epetra_CrsMatrix& ,
1986 Teuchos::FancyOStream& ) {
1988 "No ML multiplication available. This feature is currently not supported by Xpetra.");
1989 TEUCHOS_UNREACHABLE_RETURN(Teuchos::null);
1991 #endif // ifdef HAVE_XPETRA_EPETRAEXT
2005 Teuchos::FancyOStream& fos,
2006 bool doFillComplete =
true,
2007 bool doOptimizeStorage =
true) {
2009 "TwoMatrixMultiply for BlockedCrsMatrix not implemented for transposeA==true or transposeB==true");
2018 RCP<BlockedCrsMatrix> C = rcp(
new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 ));
2020 for (
size_t i = 0; i < A.
Rows(); ++i) {
2021 for (
size_t j = 0; j < B.
Cols(); ++j) {
2024 for (
size_t l = 0; l < B.
Rows(); ++l) {
2028 if (crmat1.is_null() || crmat2.is_null())
2036 if (unwrap1.is_null() != unwrap2.is_null()) {
2037 if (unwrap1 != Teuchos::null && unwrap1->Rows() == 1 && unwrap1->Cols() == 1)
2039 if (unwrap2 != Teuchos::null && unwrap2->Rows() == 1 && unwrap2->Cols() == 1)
2040 crmat2 = unwrap2->getCrsMatrix();
2044 RCP<CrsMatrixWrap> crop1 = Teuchos::rcp_dynamic_cast<
CrsMatrixWrap>(crmat1);
2045 RCP<CrsMatrixWrap> crop2 = Teuchos::rcp_dynamic_cast<
CrsMatrixWrap>(crmat2);
2047 "A and B must be either both (compatible) BlockedCrsMatrix objects or both CrsMatrixWrap objects.");
2050 if (!crop1.is_null())
2051 Teuchos::rcp_const_cast<CrsGraph>(crmat1->getCrsGraph())->computeGlobalConstants();
2052 if (!crop2.is_null())
2053 Teuchos::rcp_const_cast<CrsGraph>(crmat2->getCrsGraph())->computeGlobalConstants();
2056 "crmat1 does not have global constants");
2058 "crmat2 does not have global constants");
2060 if (crmat1->getGlobalNumEntries() == 0 || crmat2->getGlobalNumEntries() == 0)
2064 RCP<Matrix> temp = Teuchos::null;
2066 if (crop1 != Teuchos::null && crop2 != Teuchos::null)
2067 temp =
Multiply(*crop1,
false, *crop2,
false, fos);
2069 RCP<BlockedCrsMatrix> bop1 = Teuchos::rcp_dynamic_cast<
BlockedCrsMatrix>(crmat1);
2070 RCP<BlockedCrsMatrix> bop2 = Teuchos::rcp_dynamic_cast<
BlockedCrsMatrix>(crmat2);
2071 TEUCHOS_TEST_FOR_EXCEPTION(bop1.is_null() ==
true,
Xpetra::Exceptions::BadCast,
"A is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
2072 TEUCHOS_TEST_FOR_EXCEPTION(bop2.is_null() ==
true,
Xpetra::Exceptions::BadCast,
"B is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
2073 TEUCHOS_TEST_FOR_EXCEPTION(bop1->Cols() != bop2->Rows(),
Xpetra::Exceptions::RuntimeError,
"A has " << bop1->Cols() <<
" columns and B has " << bop2->Rows() <<
" rows. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
2074 TEUCHOS_TEST_FOR_EXCEPTION(bop1->getDomainMap()->isSameAs(*(bop2->getRangeMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Domain map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
2077 temp =
TwoMatrixMultiplyBlock(*bop1, transposeA, *bop2, transposeB, fos, doFillComplete, doOptimizeStorage);
2079 RCP<BlockedCrsMatrix> btemp = Teuchos::rcp_dynamic_cast<
BlockedCrsMatrix>(temp);
2080 TEUCHOS_TEST_FOR_EXCEPTION(btemp->Rows() != bop1->Rows(),
Xpetra::Exceptions::RuntimeError,
"Number of block rows of local blocked operator is " << btemp->Rows() <<
" but should be " << bop1->Rows() <<
". (TwoMatrixMultiplyBlock)");
2081 TEUCHOS_TEST_FOR_EXCEPTION(btemp->Cols() != bop2->Cols(),
Xpetra::Exceptions::RuntimeError,
"Number of block cols of local blocked operator is " << btemp->Cols() <<
" but should be " << bop2->Cols() <<
". (TwoMatrixMultiplyBlock)");
2082 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getFullMap()->isSameAs(*(bop1->getRangeMapExtractor()->getFullMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Range map of local blocked operator should be same as first operator. (TwoMatrixMultiplyBlock)");
2083 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getFullMap()->isSameAs(*(bop2->getDomainMapExtractor()->getFullMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Domain map of local blocked operator should be same as second operator. (TwoMatrixMultiplyBlock)");
2084 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getThyraMode() != bop1->getRangeMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Thyra mode of local range map extractor incompatible with range map extractor of A (TwoMatrixMultiplyBlock)");
2085 TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getThyraMode() != bop2->getDomainMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Thyra mode of local domain map extractor incompatible with domain map extractor of B (TwoMatrixMultiplyBlock)");
2090 RCP<Matrix> addRes = null;
2099 if (!Cij.is_null()) {
2100 if (Cij->isFillComplete())
2103 C->setMatrix(i, j, Cij);
2105 C->setMatrix(i, j, Teuchos::null);
2130 "TwoMatrixAdd: matrix row maps are not the same.");
2133 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
2138 int rv = EpetraExt::MatrixMatrix::Add(epA, transposeA, alpha, epB, beta);
2142 std::ostringstream buf;
2147 #ifdef HAVE_XPETRA_TPETRA
2148 #if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))) || \
2149 (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))))
2155 Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, beta);
2178 const Matrix& B,
bool transposeB,
const SC& beta,
2179 RCP<Matrix>& C, Teuchos::FancyOStream& fos,
bool AHasFixedNnzPerRow =
false) {
2180 RCP<const Matrix> rcpA = Teuchos::rcpFromRef(A);
2181 RCP<const Matrix> rcpB = Teuchos::rcpFromRef(B);
2182 RCP<const BlockedCrsMatrix> rcpBopA = Teuchos::rcp_dynamic_cast<
const BlockedCrsMatrix>(rcpA);
2183 RCP<const BlockedCrsMatrix> rcpBopB = Teuchos::rcp_dynamic_cast<
const BlockedCrsMatrix>(rcpB);
2185 if (rcpBopA == Teuchos::null && rcpBopB == Teuchos::null) {
2187 "TwoMatrixAdd: matrix row maps are not the same.");
2190 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
2194 size_t maxNzInA = 0;
2195 size_t maxNzInB = 0;
2196 size_t numLocalRows = 0;
2203 if (maxNzInA == 1 || maxNzInB == 1 || AHasFixedNnzPerRow) {
2206 Teuchos::ArrayRCP<size_t> exactNnzPerRow(numLocalRows);
2208 if ((maxNzInA == 1 && maxNzInB > 1) || AHasFixedNnzPerRow) {
2209 for (
size_t i = 0; i < numLocalRows; ++i)
2213 for (
size_t i = 0; i < numLocalRows; ++i)
2217 fos <<
"MatrixMatrix::TwoMatrixAdd : special case detected (one matrix has a fixed nnz per row)"
2218 <<
", using static profiling" << std::endl;
2227 fos <<
"MatrixMatrix::TwoMatrixAdd : ** WARNING ** estimate could be badly wrong because second summand is transposed" << std::endl;
2230 Epetra_CrsMatrix* ref2epC = &*epC;
2233 int rv = EpetraExt::MatrixMatrix::Add(epA, transposeA, alpha, epB, transposeB, beta, ref2epC);
2241 #ifdef HAVE_XPETRA_TPETRA
2242 #if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))) || \
2243 (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))))
2247 using tcrs_matrix_type = Tpetra::CrsMatrix<SC, LO, GO, NO>;
2250 C = helpers::tpetraAdd(tpA, transposeA, alpha, tpB, transposeB, beta);
2258 if (A.
IsView(
"stridedMaps")) C->CreateView(
"stridedMaps", rcpFromRef(A));
2259 if (B.
IsView(
"stridedMaps")) C->CreateView(
"stridedMaps", rcpFromRef(B));
2263 else if (rcpBopA == Teuchos::null && rcpBopB != Teuchos::null) {
2264 RCP<const MapExtractor> rgmapextractor = rcpBopB->getRangeMapExtractor();
2265 RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
2271 for (
size_t j = 0; j < rcpBopB->Cols(); ++j) {
2272 RCP<Matrix> Cij = Teuchos::null;
2273 if (rcpA != Teuchos::null &&
2274 rcpBopB->getMatrix(i, j) != Teuchos::null) {
2277 *(rcpBopB->getMatrix(i, j)), transposeB, beta,
2278 Cij, fos, AHasFixedNnzPerRow);
2279 }
else if (rcpA == Teuchos::null &&
2280 rcpBopB->getMatrix(i, j) != Teuchos::null) {
2281 Cij = rcpBopB->getMatrix(i, j);
2282 }
else if (rcpA != Teuchos::null &&
2283 rcpBopB->getMatrix(i, j) == Teuchos::null) {
2284 Cij = Teuchos::rcp_const_cast<
Matrix>(rcpA);
2286 Cij = Teuchos::null;
2289 if (!Cij.is_null()) {
2290 if (Cij->isFillComplete())
2292 Cij->fillComplete();
2293 bC->setMatrix(i, j, Cij);
2295 bC->setMatrix(i, j, Teuchos::null);
2300 else if (rcpBopA != Teuchos::null && rcpBopB == Teuchos::null) {
2301 RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
2302 RCP<const MapExtractor> domapextractor = rcpBopA->getDomainMapExtractor();
2308 for (
size_t i = 0; i < rcpBopA->Rows(); ++i) {
2309 RCP<Matrix> Cij = Teuchos::null;
2310 if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
2311 rcpB != Teuchos::null) {
2313 TwoMatrixAdd(*(rcpBopA->getMatrix(i, j)), transposeA, alpha,
2314 *rcpB, transposeB, beta,
2315 Cij, fos, AHasFixedNnzPerRow);
2316 }
else if (rcpBopA->getMatrix(i, j) == Teuchos::null &&
2317 rcpB != Teuchos::null) {
2318 Cij = Teuchos::rcp_const_cast<
Matrix>(rcpB);
2319 }
else if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
2320 rcpB == Teuchos::null) {
2321 Cij = rcpBopA->getMatrix(i, j);
2323 Cij = Teuchos::null;
2326 if (!Cij.is_null()) {
2327 if (Cij->isFillComplete())
2329 Cij->fillComplete();
2330 bC->setMatrix(i, j, Cij);
2332 bC->setMatrix(i, j, Teuchos::null);
2339 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA.is_null() ==
true,
Xpetra::Exceptions::BadCast,
"A is not a BlockedCrsMatrix. (TwoMatrixAdd)");
2340 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopB.is_null() ==
true,
Xpetra::Exceptions::BadCast,
"B is not a BlockedCrsMatrix. (TwoMatrixAdd)");
2341 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows() != rcpBopB->Rows(),
Xpetra::Exceptions::RuntimeError,
"A has " << rcpBopA->Rows() <<
" rows and B has " << rcpBopA->Rows() <<
" rows. Matrices are not compatible! (TwoMatrixAdd)");
2342 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows() != rcpBopB->Rows(),
Xpetra::Exceptions::RuntimeError,
"A has " << rcpBopA->Cols() <<
" cols and B has " << rcpBopA->Cols() <<
" cols. Matrices are not compatible! (TwoMatrixAdd)");
2343 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMap()->isSameAs(*(rcpBopB->getRangeMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Range map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixAdd)");
2344 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMap()->isSameAs(*(rcpBopB->getDomainMap())) ==
false,
Xpetra::Exceptions::RuntimeError,
"Domain map of A is not the same as domain map of B. Matrices are not compatible! (TwoMatrixAdd)");
2345 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMapExtractor()->getThyraMode() != rcpBopB->getRangeMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Different Thyra/Xpetra style gids in RangeMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
2346 TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMapExtractor()->getThyraMode() != rcpBopB->getDomainMapExtractor()->getThyraMode(),
Xpetra::Exceptions::RuntimeError,
"Different Thyra/Xpetra style gids in DomainMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
2348 RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
2349 RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
2354 for (
size_t i = 0; i < rcpBopA->Rows(); ++i) {
2355 for (
size_t j = 0; j < rcpBopB->Cols(); ++j) {
2357 RCP<Matrix> Cij = Teuchos::null;
2358 if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
2359 rcpBopB->getMatrix(i, j) != Teuchos::null) {
2362 TwoMatrixAdd(*(rcpBopA->getMatrix(i, j)), transposeA, alpha,
2363 *(rcpBopB->getMatrix(i, j)), transposeB, beta,
2364 Cij, fos, AHasFixedNnzPerRow);
2365 }
else if (rcpBopA->getMatrix(i, j) == Teuchos::null &&
2366 rcpBopB->getMatrix(i, j) != Teuchos::null) {
2367 Cij = rcpBopB->getMatrix(i, j);
2368 }
else if (rcpBopA->getMatrix(i, j) != Teuchos::null &&
2369 rcpBopB->getMatrix(i, j) == Teuchos::null) {
2370 Cij = rcpBopA->getMatrix(i, j);
2372 Cij = Teuchos::null;
2375 if (!Cij.is_null()) {
2376 if (Cij->isFillComplete())
2379 Cij->fillComplete();
2380 bC->setMatrix(i, j, Cij);
2382 bC->setMatrix(i, j, Teuchos::null);
2391 #endif // HAVE_XPETRA_EPETRA
2395 #define XPETRA_MATRIXMATRIX_SHORT
RCP< CrsMatrix > getCrsMatrix() const
static bool isTpetraBlockCrs(const Matrix &Op)
static Tpetra::CrsMatrix< SC, LO, GO, NO > & Op2NonConstTpetraCrs(const Matrix &Op)
std::string toString(Xpetra::UnderlyingLib lib)
Convert a Xpetra::UnderlyingLib to a std::string.
static void TwoMatrixAdd(const Matrix &A, bool transposeA, const SC &alpha, const Matrix &B, bool transposeB, const SC &beta, RCP< Matrix > &C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow=false)
Helper function to calculate C = alpha*A + beta*B.
static void TwoMatrixAdd(const Matrix &A, bool transposeA, const SC &alpha, const Matrix &B, bool transposeB, const SC &beta, RCP< Matrix > &C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow=false)
Helper function to calculate C = alpha*A + beta*B.
static const Tpetra::CrsMatrix< SC, LO, GO, NO > & Op2TpetraCrs(const Matrix &Op)
static RCP< const Tpetra::CrsMatrix< SC, LO, GO, NO > > Op2TpetraCrs(RCP< Matrix > Op)
virtual global_size_t getGlobalNumRows() const =0
Returns the number of global rows in this matrix.
static Teuchos::RCP< Matrix > tpetraAdd(const tcrs_matrix_type &A, bool transposeA, const typename tcrs_matrix_type::scalar_type alpha, const tcrs_matrix_type &B, bool transposeB, const typename tcrs_matrix_type::scalar_type beta)
static bool isTpetraCrs(RCP< Matrix > Op)
const RCP< const Map > getRangeMap() const
Returns the Map associated with the range of this operator.
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, RCP< Matrix > C_in, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > ¶ms=null)
Helper function to do matrix-matrix multiply.
bool isFillComplete() const
Returns true if fillComplete() has been called and the matrix is in compute mode. ...
static Epetra_CrsMatrix & Op2NonConstEpetraCrs(const Matrix &Op)
Xpetra utility class containing transformation routines between Xpetra::Matrix and Epetra/Tpetra obje...
static RCP< Matrix > Build(const RCP< const Map > &rowMap)
virtual void resumeFill(const RCP< ParameterList > ¶ms=null)=0
static RCP< Tpetra::CrsMatrix< SC, LO, GO, NO > > Op2NonConstTpetraCrs(RCP< Matrix > Op)
virtual LocalOrdinal GetStorageBlockSize() const =0
Returns the block size of the storage mechanism, which is usually 1, except for Tpetra::BlockCrsMatri...
Exception throws to report errors in the internal logical of the program.
static RCP< BlockedCrsMatrix > TwoMatrixMultiplyBlock(const BlockedCrsMatrix &A, bool transposeA, const BlockedCrsMatrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true)
Helper function to do matrix-matrix multiply "in-place".
Teuchos::RCP< Matrix > getCrsMatrix() const
return unwrap 1x1 blocked operators
static bool isTpetraBlockCrs(RCP< Matrix > Op)
static const Epetra_CrsMatrix & Op2EpetraCrs(const Matrix &Op)
static const Tpetra::BlockCrsMatrix< SC, LO, GO, NO > & Op2TpetraBlockCrs(const Matrix &Op)
Exception indicating invalid cast attempted.
virtual void fillComplete(const RCP< const Map > &domainMap, const RCP< const Map > &rangeMap, const RCP< ParameterList > ¶ms=null)=0
Signal that data entry is complete, specifying domain and range maps.
static void TwoMatrixAdd(const Matrix &A, bool transposeA, const SC &alpha, const Matrix &B, bool transposeB, const SC &beta, RCP< Matrix > &C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow=false)
Helper function to calculate C = alpha*A + beta*B.
static RCP< Epetra_CrsMatrix > MLTwoMatrixMultiply(const Epetra_CrsMatrix &, const Epetra_CrsMatrix &, Teuchos::FancyOStream &)
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool callFillCompleteOnResult=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > ¶ms=null)
Helper function to do matrix-matrix multiply.
bool IsView(const viewLabel_t viewLabel) const
Teuchos::RCP< Matrix > getMatrix(size_t r, size_t c) const
return block (r,c)
virtual bool isFillComplete() const =0
Returns true if fillComplete() has been called and the matrix is in compute mode. ...
virtual size_t Cols() const
number of column blocks
void CreateView(viewLabel_t viewLabel, const RCP< const Map > &rowMap, const RCP< const Map > &colMap)
static void Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Matrix &C, bool call_FillComplete_on_result=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > ¶ms=null)
static RCP< Tpetra::BlockCrsMatrix< SC, LO, GO, NO > > Op2NonConstTpetraBlockCrs(RCP< Matrix > Op)
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, RCP< Matrix > C_in, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > ¶ms=null)
Helper function to do matrix-matrix multiply.
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, RCP< Matrix > C_in, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > ¶ms=null)
Helper function to do matrix-matrix multiply.
virtual const Teuchos::RCP< const map_type > getRangeMap() const =0
The Map associated with the range of this operator, which must be compatible with Y...
virtual size_t getNumEntriesInLocalRow(LocalOrdinal localRow) const =0
Returns the current number of entries on this node in the specified local row.
static void Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Matrix &C, bool call_FillComplete_on_result=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > ¶ms=null)
static RCP< BlockedCrsMatrix > TwoMatrixMultiplyBlock(const BlockedCrsMatrix &A, bool transposeA, const BlockedCrsMatrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true)
Helper function to do matrix-matrix multiply "in-place".
virtual size_t getLocalNumRows() const =0
Returns the number of matrix rows owned on the calling node.
static bool isTpetraCrs(const Matrix &Op)
static void TwoMatrixAdd(const Matrix &A, bool transposeA, SC alpha, Matrix &B, SC beta)
Helper function to calculate B = alpha*A + beta*B.
Tpetra::CrsMatrix< SC, LO, GO, NO > tcrs_matrix_type
static void epetraExtMult(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Matrix &C, bool fillCompleteResult)
static RCP< const Epetra_CrsMatrix > Op2EpetraCrs(RCP< Matrix > Op)
RCP< const MapExtractor > getDomainMapExtractor() const
Returns map extractor for domain map.
Tpetra::KokkosCompat::KokkosSerialWrapperNode EpetraNode
const RCP< const Map > getDomainMap() const
Returns the Map associated with the domain of this operator.
void replaceCrsMatrix(RCP< CrsMatrix > &M)
Expert only.
static void Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Matrix &C, bool call_FillComplete_on_result=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > ¶ms=null)
static RCP< Epetra_CrsMatrix > Op2NonConstEpetraCrs(RCP< Matrix > Op)
static RCP< const Tpetra::BlockCrsMatrix< SC, LO, GO, NO > > Op2TpetraBlockCrs(RCP< Matrix > Op)
Exception throws to report incompatible objects (like maps).
static void TwoMatrixAdd(const Matrix &A, bool transposeA, SC alpha, Matrix &B, SC beta)
Helper function to calculate B = alpha*A + beta*B.
virtual global_size_t getGlobalNumEntries() const =0
Returns the global number of entries in this matrix.
Concrete implementation of Xpetra::Matrix.
virtual size_t Rows() const
number of row blocks
virtual const Teuchos::RCP< const map_type > getDomainMap() const =0
The Map associated with the domain of this operator, which must be compatible with X...
virtual size_t getLocalMaxNumRowEntries() const =0
Returns the maximum number of entries across all rows/columns on this node.
static RCP< Epetra_CrsMatrix > MLTwoMatrixMultiply(const Epetra_CrsMatrix &epA, const Epetra_CrsMatrix &epB, Teuchos::FancyOStream &fos)
static Tpetra::BlockCrsMatrix< SC, LO, GO, NO > & Op2NonConstTpetraBlockCrs(const Matrix &Op)
static RCP< BlockedCrsMatrix > TwoMatrixMultiplyBlock(const BlockedCrsMatrix &A, bool transposeA, const BlockedCrsMatrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true)
Helper function to do matrix-matrix multiply "in-place".
virtual const RCP< const Map > & getRowMap() const
Returns the Map that describes the row distribution in this matrix.
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool callFillCompleteOnResult=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > ¶ms=null)
Helper function to do matrix-matrix multiply.
static RCP< Epetra_CrsMatrix > MLTwoMatrixMultiply(const Epetra_CrsMatrix &epA, const Epetra_CrsMatrix &epB, Teuchos::FancyOStream &fos)
static void TwoMatrixAdd(const Matrix &A, bool transposeA, SC alpha, Matrix &B, SC beta)
Helper function to calculate B = alpha*A + beta*B.
Xpetra-specific matrix class.
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool callFillCompleteOnResult=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > ¶ms=null)
Helper function to do matrix-matrix multiply.
RCP< const MapExtractor > getRangeMapExtractor() const
Returns map extractor class for range map.