47 #include "Teko_Config.h"
51 #include "Thyra_MultiVectorStdOps.hpp"
52 #include "Thyra_ZeroLinearOpBase.hpp"
53 #include "Thyra_DefaultDiagonalLinearOp.hpp"
54 #include "Thyra_DefaultAddedLinearOp.hpp"
55 #include "Thyra_DefaultScaledAdjointLinearOp.hpp"
56 #include "Thyra_DefaultMultipliedLinearOp.hpp"
57 #include "Thyra_DefaultZeroLinearOp.hpp"
58 #include "Thyra_DefaultProductMultiVector.hpp"
59 #include "Thyra_DefaultProductVectorSpace.hpp"
60 #include "Thyra_MultiVectorStdOps.hpp"
61 #include "Thyra_VectorStdOps.hpp"
62 #include "Thyra_SpmdVectorBase.hpp"
65 #ifdef TEKO_HAVE_EPETRA
66 #include "Thyra_EpetraExtDiagScaledMatProdTransformer.hpp"
67 #include "Thyra_EpetraExtDiagScalingTransformer.hpp"
68 #include "Thyra_EpetraExtAddTransformer.hpp"
69 #include "Thyra_get_Epetra_Operator.hpp"
70 #include "Thyra_EpetraThyraWrappers.hpp"
71 #include "Thyra_EpetraOperatorWrapper.hpp"
72 #include "Thyra_EpetraLinearOp.hpp"
76 #include "Teuchos_Array.hpp"
79 #ifdef TEKO_HAVE_EPETRA
80 #include "Epetra_Operator.h"
81 #include "Epetra_CrsGraph.h"
82 #include "Epetra_CrsMatrix.h"
83 #include "Epetra_Vector.h"
84 #include "Epetra_Map.h"
86 #include "EpetraExt_Transpose_RowMatrix.h"
87 #include "EpetraExt_MatrixMatrix.h"
89 #include "Teko_EpetraHelpers.hpp"
90 #include "Teko_EpetraOperatorWrapper.hpp"
94 #include "AnasaziBasicEigenproblem.hpp"
95 #include "AnasaziThyraAdapter.hpp"
96 #include "AnasaziBlockKrylovSchurSolMgr.hpp"
97 #include "AnasaziBlockKrylovSchur.hpp"
98 #include "AnasaziStatusTestMaxIters.hpp"
101 #ifdef Teko_ENABLE_Isorropia
102 #include "Isorropia_EpetraProber.hpp"
106 #include "Teko_TpetraHelpers.hpp"
107 #include "Teko_TpetraOperatorWrapper.hpp"
110 #include "Thyra_TpetraLinearOp.hpp"
111 #include "Tpetra_CrsMatrix.hpp"
112 #include "Tpetra_Vector.hpp"
113 #include "Thyra_TpetraThyraWrappers.hpp"
114 #include "TpetraExt_MatrixMatrix.hpp"
115 #include "Tpetra_RowMatrixTransposer.hpp"
123 using Teuchos::rcp_dynamic_cast;
124 #ifdef Teko_ENABLE_Isorropia
125 using Isorropia::Epetra::Prober;
128 const Teuchos::RCP<Teuchos::FancyOStream> getOutputStream() {
129 Teuchos::RCP<Teuchos::FancyOStream> os = Teuchos::VerboseObjectBase::getDefaultOStream();
137 inline double dist(
int dim,
double *coords,
int row,
int col) {
139 for (
int i = 0; i < dim; i++)
140 value += std::pow(coords[dim * row + i] - coords[dim * col + i], 2.0);
143 return std::sqrt(value);
147 inline double dist(
double *x,
double *y,
double *z,
int stride,
int row,
int col) {
149 if (x != 0) value += std::pow(x[stride * row] - x[stride * col], 2.0);
150 if (y != 0) value += std::pow(y[stride * row] - y[stride * col], 2.0);
151 if (z != 0) value += std::pow(z[stride * row] - z[stride * col], 2.0);
154 return std::sqrt(value);
175 #ifdef TEKO_HAVE_EPETRA
176 RCP<Epetra_CrsMatrix> buildGraphLaplacian(
int dim,
double *coords,
177 const Epetra_CrsMatrix &stencil) {
180 RCP<Epetra_CrsMatrix> gl = rcp(
181 new Epetra_CrsMatrix(Copy, stencil.RowMap(), stencil.ColMap(), stencil.MaxNumEntries() + 1),
185 std::vector<double> rowData(stencil.GlobalMaxNumEntries() + 1);
186 std::vector<int> rowInd(stencil.GlobalMaxNumEntries() + 1);
189 for (
int j = 0; j < gl->NumMyRows(); j++) {
190 int row = gl->GRID(j);
191 double diagValue = 0.0;
196 stencil.ExtractGlobalRowCopy(row, stencil.MaxNumEntries(), rowSz, &rowData[0], &rowInd[0]);
199 for (
int i = 0; i < rowSz; i++) {
203 double value = rowData[i];
204 if (value == 0)
continue;
208 double d = dist(dim, coords, row, col);
209 rowData[i] = -1.0 / d;
210 diagValue += rowData[i];
217 rowData[rowSz] = -diagValue;
221 rowData[diagInd] = -diagValue;
222 rowInd[diagInd] = row;
226 TEUCHOS_TEST_FOR_EXCEPT(gl->InsertGlobalValues(row, rowSz, &rowData[0], &rowInd[0]));
235 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> buildGraphLaplacian(
236 int dim, ST *coords,
const Tpetra::CrsMatrix<ST, LO, GO, NT> &stencil) {
239 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> gl = rcp(
new Tpetra::CrsMatrix<ST, LO, GO, NT>(
240 stencil.getRowMap(), stencil.getColMap(), stencil.getGlobalMaxNumRowEntries() + 1));
243 auto rowInd =
typename Tpetra::CrsMatrix<ST, LO, GO, NT>::nonconst_global_inds_host_view_type(
244 Kokkos::ViewAllocateWithoutInitializing(
"rowIndices"),
245 stencil.getGlobalMaxNumRowEntries() + 1);
246 auto rowData =
typename Tpetra::CrsMatrix<ST, LO, GO, NT>::nonconst_values_host_view_type(
247 Kokkos::ViewAllocateWithoutInitializing(
"rowIndices"),
248 stencil.getGlobalMaxNumRowEntries() + 1);
251 for (LO j = 0; j < (LO)gl->getLocalNumRows(); j++) {
252 GO row = gl->getRowMap()->getGlobalElement(j);
258 stencil.getGlobalRowCopy(row, rowInd, rowData, rowSz);
261 for (
size_t i = 0; i < rowSz; i++) {
265 ST value = rowData[i];
266 if (value == 0)
continue;
270 ST d = dist(dim, coords, row, col);
271 rowData[i] = -1.0 / d;
272 diagValue += rowData(i);
279 rowData(rowSz) = -diagValue;
283 rowData(diagInd) = -diagValue;
284 rowInd(diagInd) = row;
288 gl->replaceGlobalValues(row, rowInd, rowData);
318 #ifdef TEKO_HAVE_EPETRA
319 RCP<Epetra_CrsMatrix> buildGraphLaplacian(
double *x,
double *y,
double *z,
int stride,
320 const Epetra_CrsMatrix &stencil) {
323 RCP<Epetra_CrsMatrix> gl = rcp(
324 new Epetra_CrsMatrix(Copy, stencil.RowMap(), stencil.ColMap(), stencil.MaxNumEntries() + 1),
328 std::vector<double> rowData(stencil.GlobalMaxNumEntries() + 1);
329 std::vector<int> rowInd(stencil.GlobalMaxNumEntries() + 1);
332 for (
int j = 0; j < gl->NumMyRows(); j++) {
333 int row = gl->GRID(j);
334 double diagValue = 0.0;
339 stencil.ExtractGlobalRowCopy(row, stencil.MaxNumEntries(), rowSz, &rowData[0], &rowInd[0]);
342 for (
int i = 0; i < rowSz; i++) {
346 double value = rowData[i];
347 if (value == 0)
continue;
351 double d = dist(x, y, z, stride, row, col);
352 rowData[i] = -1.0 / d;
353 diagValue += rowData[i];
360 rowData[rowSz] = -diagValue;
364 rowData[diagInd] = -diagValue;
365 rowInd[diagInd] = row;
369 TEUCHOS_TEST_FOR_EXCEPT(gl->InsertGlobalValues(row, rowSz, &rowData[0], &rowInd[0]));
378 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> buildGraphLaplacian(
379 ST *x, ST *y, ST *z, GO stride,
const Tpetra::CrsMatrix<ST, LO, GO, NT> &stencil) {
382 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> gl =
383 rcp(
new Tpetra::CrsMatrix<ST, LO, GO, NT>(stencil.getRowMap(), stencil.getColMap(),
384 stencil.getGlobalMaxNumRowEntries() + 1),
388 auto rowInd =
typename Tpetra::CrsMatrix<ST, LO, GO, NT>::nonconst_global_inds_host_view_type(
389 Kokkos::ViewAllocateWithoutInitializing(
"rowIndices"),
390 stencil.getGlobalMaxNumRowEntries() + 1);
391 auto rowData =
typename Tpetra::CrsMatrix<ST, LO, GO, NT>::nonconst_values_host_view_type(
392 Kokkos::ViewAllocateWithoutInitializing(
"rowIndices"),
393 stencil.getGlobalMaxNumRowEntries() + 1);
396 for (LO j = 0; j < (LO)gl->getLocalNumRows(); j++) {
397 GO row = gl->getRowMap()->getGlobalElement(j);
403 stencil.getGlobalRowCopy(row, rowInd, rowData, rowSz);
406 for (
size_t i = 0; i < rowSz; i++) {
410 ST value = rowData[i];
411 if (value == 0)
continue;
415 ST d = dist(x, y, z, stride, row, col);
416 rowData[i] = -1.0 / d;
417 diagValue += rowData(i);
424 rowData(rowSz) = -diagValue;
428 rowData(diagInd) = -diagValue;
429 rowInd(diagInd) = row;
433 gl->replaceGlobalValues(row, rowInd, rowData);
456 void applyOp(
const LinearOp &A,
const MultiVector &x, MultiVector &y,
double alpha,
double beta) {
457 Thyra::apply(*A, Thyra::NOTRANS, *x, y.ptr(), alpha, beta);
475 void applyTransposeOp(
const LinearOp &A,
const MultiVector &x, MultiVector &y,
double alpha,
477 Thyra::apply(*A, Thyra::TRANS, *x, y.ptr(), alpha, beta);
482 void update(
double alpha,
const MultiVector &x,
double beta, MultiVector &y) {
483 Teuchos::Array<double> scale;
484 Teuchos::Array<Teuchos::Ptr<const Thyra::MultiVectorBase<double>>> vec;
487 scale.push_back(alpha);
488 vec.push_back(x.ptr());
491 Thyra::linear_combination<double>(scale, vec, beta, y.ptr());
495 BlockedLinearOp getUpperTriBlocks(
const BlockedLinearOp &blo,
bool callEndBlockFill) {
496 int rows = blockRowCount(blo);
498 TEUCHOS_ASSERT(rows == blockColCount(blo));
500 RCP<const Thyra::ProductVectorSpaceBase<double>> range = blo->productRange();
501 RCP<const Thyra::ProductVectorSpaceBase<double>> domain = blo->productDomain();
504 BlockedLinearOp upper = createBlockedOp();
507 upper->beginBlockFill(rows, rows);
509 for (
int i = 0; i < rows; i++) {
513 RCP<const Thyra::LinearOpBase<double>> zed =
514 Thyra::zero<double>(range->getBlock(i), domain->getBlock(i));
515 upper->setBlock(i, i, zed);
517 for (
int j = i + 1; j < rows; j++) {
519 LinearOp uij = blo->getBlock(i, j);
522 if (uij != Teuchos::null) upper->setBlock(i, j, uij);
525 if (callEndBlockFill) upper->endBlockFill();
531 BlockedLinearOp getLowerTriBlocks(
const BlockedLinearOp &blo,
bool callEndBlockFill) {
532 int rows = blockRowCount(blo);
534 TEUCHOS_ASSERT(rows == blockColCount(blo));
536 RCP<const Thyra::ProductVectorSpaceBase<double>> range = blo->productRange();
537 RCP<const Thyra::ProductVectorSpaceBase<double>> domain = blo->productDomain();
540 BlockedLinearOp lower = createBlockedOp();
543 lower->beginBlockFill(rows, rows);
545 for (
int i = 0; i < rows; i++) {
549 RCP<const Thyra::LinearOpBase<double>> zed =
550 Thyra::zero<double>(range->getBlock(i), domain->getBlock(i));
551 lower->setBlock(i, i, zed);
553 for (
int j = 0; j < i; j++) {
555 LinearOp uij = blo->getBlock(i, j);
558 if (uij != Teuchos::null) lower->setBlock(i, j, uij);
561 if (callEndBlockFill) lower->endBlockFill();
585 BlockedLinearOp zeroBlockedOp(
const BlockedLinearOp &blo) {
586 int rows = blockRowCount(blo);
588 TEUCHOS_ASSERT(rows == blockColCount(blo));
590 RCP<const Thyra::ProductVectorSpaceBase<double>> range = blo->productRange();
591 RCP<const Thyra::ProductVectorSpaceBase<double>> domain = blo->productDomain();
594 BlockedLinearOp zeroOp = createBlockedOp();
597 zeroOp->beginBlockFill(rows, rows);
599 for (
int i = 0; i < rows; i++) {
603 RCP<const Thyra::LinearOpBase<double>> zed =
604 Thyra::zero<double>(range->getBlock(i), domain->getBlock(i));
605 zeroOp->setBlock(i, i, zed);
612 bool isZeroOp(
const LinearOp op) {
614 if (op == Teuchos::null)
return true;
617 LinearOp test = rcp_dynamic_cast<
const Thyra::ZeroLinearOpBase<double>>(op);
620 if (test != Teuchos::null)
return true;
624 Thyra::EOpTransp transp = Thyra::NOTRANS;
625 RCP<const Thyra::LinearOpBase<ST>> wrapped_op;
626 Thyra::unwrap(op, &scalar, &transp, &wrapped_op);
627 test = rcp_dynamic_cast<
const Thyra::ZeroLinearOpBase<double>>(wrapped_op);
628 return test != Teuchos::null;
631 std::pair<ModifiableLinearOp, bool> getAbsRowSumMatrixEpetra(
const LinearOp &op) {
632 #ifndef TEKO_HAVE_EPETRA
633 return std::make_pair(ModifiableLinearOp{},
false);
635 RCP<const Epetra_CrsMatrix> eCrsOp;
637 const auto eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op);
640 return std::make_pair(ModifiableLinearOp{},
false);
643 eCrsOp = rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
646 const auto ptrDiag = rcp(
new Epetra_Vector(eCrsOp->RowMap()));
647 Epetra_Vector &diag = *ptrDiag;
651 for (
int i = 0; i < eCrsOp->NumMyRows(); i++) {
654 eCrsOp->ExtractMyRowView(i, numEntries, values);
657 for (
int j = 0; j < numEntries; j++) diag[i] += std::abs(values[j]);
661 return std::make_pair(Teko::Epetra::thyraDiagOp(ptrDiag, eCrsOp->RowMap(),
662 "absRowSum( " + op->getObjectLabel() +
" )"),
667 std::pair<ModifiableLinearOp, bool> getAbsRowSumMatrixTpetra(
const LinearOp &op) {
668 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp;
670 const auto tOp = rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op);
672 tCrsOp = rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
676 const auto ptrDiag = Tpetra::createVector<ST, LO, GO, NT>(tCrsOp->getRowMap());
677 auto &diag = *ptrDiag;
681 for (LO i = 0; i < (LO)tCrsOp->getLocalNumRows(); i++) {
682 auto numEntries = tCrsOp->getNumEntriesInLocalRow(i);
683 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::local_inds_host_view_type indices;
684 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::values_host_view_type values;
685 tCrsOp->getLocalRowView(i, indices, values);
688 for (
size_t j = 0; j < numEntries; j++) diag.sumIntoLocalValue(i, std::abs(values(j)));
692 return std::make_pair(
693 Teko::TpetraHelpers::thyraDiagOp(ptrDiag, *tCrsOp->getRowMap(),
694 "absRowSum( " + op->getObjectLabel() +
" ))"),
706 ModifiableLinearOp getAbsRowSumMatrix(
const LinearOp &op) {
708 auto eResult = getAbsRowSumMatrixEpetra(op);
709 if (eResult.second) {
710 return eResult.first;
713 auto tResult = getAbsRowSumMatrixTpetra(op);
714 if (tResult.second) {
715 return tResult.first;
717 throw std::logic_error(
"Neither Epetra nor Tpetra");
719 }
catch (std::exception &e) {
720 auto out = Teuchos::VerboseObjectBase::getDefaultOStream();
722 *out <<
"Teko: getAbsRowSumMatrix requires an Epetra_CrsMatrix or a "
723 "Tpetra::CrsMatrix\n";
724 *out <<
" Could not extract an Epetra_Operator or a Tpetra_Operator "
726 << op->description() << std::endl;
728 *out <<
" Could not cast an Epetra_Operator to a Epetra_CrsMatrix or "
729 "a Tpetra_Operator to a Tpetra::CrsMatrix\n";
731 *out <<
"*** THROWN EXCEPTION ***\n";
732 *out << e.what() << std::endl;
733 *out <<
"************************\n";
747 ModifiableLinearOp getAbsRowSumInvMatrix(
const LinearOp &op) {
750 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_op =
751 rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(op);
752 if (blocked_op != Teuchos::null) {
753 int numRows = blocked_op->productRange()->numBlocks();
754 TEUCHOS_ASSERT(blocked_op->productDomain()->numBlocks() == numRows);
755 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_diag =
756 Thyra::defaultBlockedLinearOp<double>();
757 blocked_diag->beginBlockFill(numRows, numRows);
758 for (
int r = 0; r < numRows; ++r) {
759 for (
int c = 0; c < numRows; ++c) {
761 blocked_diag->setNonconstBlock(r, c, getAbsRowSumInvMatrix(blocked_op->getBlock(r, c)));
763 blocked_diag->setBlock(r, c,
764 Thyra::zero<double>(blocked_op->getBlock(r, c)->range(),
765 blocked_op->getBlock(r, c)->domain()));
768 blocked_diag->endBlockFill();
772 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
775 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp =
776 Teko::TpetraHelpers::getTpetraCrsMatrix(op, &scalar, &transp);
779 const RCP<Tpetra::Vector<ST, LO, GO, NT>> ptrDiag =
780 Tpetra::createVector<ST, LO, GO, NT>(tCrsOp->getRowMap());
781 Tpetra::Vector<ST, LO, GO, NT> &diag = *ptrDiag;
785 for (LO i = 0; i < (LO)tCrsOp->getLocalNumRows(); i++) {
786 LO numEntries = tCrsOp->getNumEntriesInLocalRow(i);
787 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::local_inds_host_view_type indices;
788 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::values_host_view_type values;
789 tCrsOp->getLocalRowView(i, indices, values);
792 for (LO j = 0; j < numEntries; j++) diag.sumIntoLocalValue(i, std::abs(values(j)));
795 diag.reciprocal(diag);
798 return Teko::TpetraHelpers::thyraDiagOp(ptrDiag, *tCrsOp->getRowMap(),
799 "absRowSum( " + op->getObjectLabel() +
" ))");
802 #ifdef TEKO_HAVE_EPETRA
803 RCP<const Thyra::EpetraLinearOp> eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op,
true);
804 RCP<const Epetra_CrsMatrix> eCrsOp =
805 rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
808 const RCP<Epetra_Vector> ptrDiag = rcp(
new Epetra_Vector(eCrsOp->RowMap()));
809 Epetra_Vector &diag = *ptrDiag;
813 for (
int i = 0; i < eCrsOp->NumMyRows(); i++) {
816 eCrsOp->ExtractMyRowView(i, numEntries, values);
819 for (
int j = 0; j < numEntries; j++) diag[i] += std::abs(values[j]);
821 diag.Reciprocal(diag);
824 return Teko::Epetra::thyraDiagOp(ptrDiag, eCrsOp->RowMap(),
825 "absRowSum( " + op->getObjectLabel() +
" )");
827 throw std::logic_error(
828 "getAbsRowSumInvMatrix is trying to use Epetra "
829 "code, but TEKO_HAVE_EPETRA is disabled!");
841 ModifiableLinearOp getLumpedMatrix(
const LinearOp &op) {
842 RCP<Thyra::VectorBase<ST>> ones = Thyra::createMember(op->domain());
843 RCP<Thyra::VectorBase<ST>> diag = Thyra::createMember(op->range());
846 Thyra::assign(ones.ptr(), 1.0);
850 Thyra::apply(*op, Thyra::NOTRANS, *ones, diag.ptr());
852 return rcp(
new Thyra::DefaultDiagonalLinearOp<ST>(diag));
863 ModifiableLinearOp getInvLumpedMatrix(
const LinearOp &op) {
864 RCP<Thyra::VectorBase<ST>> ones = Thyra::createMember(op->domain());
865 RCP<Thyra::VectorBase<ST>> diag = Thyra::createMember(op->range());
868 Thyra::assign(ones.ptr(), 1.0);
871 Thyra::apply(*op, Thyra::NOTRANS, *ones, diag.ptr());
872 Thyra::reciprocal(*diag, diag.ptr());
874 return rcp(
new Thyra::DefaultDiagonalLinearOp<ST>(diag));
877 const std::pair<ModifiableLinearOp, bool> getDiagonalOpEpetra(
const LinearOp &op) {
878 #ifndef TEKO_HAVE_EPETRA
879 return std::make_pair(ModifiableLinearOp{},
false);
881 RCP<const Epetra_CrsMatrix> eCrsOp;
883 const auto eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op);
885 return std::make_pair(ModifiableLinearOp{},
false);
888 eCrsOp = rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
891 const auto diag = rcp(
new Epetra_Vector(eCrsOp->RowMap()));
892 TEUCHOS_TEST_FOR_EXCEPT(eCrsOp->ExtractDiagonalCopy(*diag));
895 return std::make_pair(Teko::Epetra::thyraDiagOp(diag, eCrsOp->RowMap(),
896 "inv(diag( " + op->getObjectLabel() +
" ))"),
901 const std::pair<ModifiableLinearOp, bool> getDiagonalOpTpetra(
const LinearOp &op) {
902 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp;
904 const auto tOp = rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op);
906 return std::make_pair(ModifiableLinearOp{},
false);
909 tCrsOp = rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
913 const auto diag = Tpetra::createVector<ST, LO, GO, NT>(tCrsOp->getRowMap());
914 tCrsOp->getLocalDiagCopy(*diag);
917 return std::make_pair(
918 Teko::TpetraHelpers::thyraDiagOp(diag, *tCrsOp->getRowMap(),
919 "inv(diag( " + op->getObjectLabel() +
" ))"),
934 const ModifiableLinearOp getDiagonalOp(
const LinearOp &op) {
937 const auto eDiagOp = getDiagonalOpEpetra(op);
939 if (eDiagOp.second) {
940 return eDiagOp.first;
943 const auto tDiagOp = getDiagonalOpTpetra(op);
944 if (tDiagOp.second) {
945 return tDiagOp.first;
947 throw std::logic_error(
"Neither Epetra nor Tpetra");
948 }
catch (std::exception &e) {
949 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
951 *out <<
"Teko: getDiagonalOp requires an Epetra_CrsMatrix or a Tpetra::CrsMatrix\n";
952 *out <<
" Could not extract an Epetra_Operator or a Tpetra_Operator from a \""
953 << op->description() << std::endl;
955 *out <<
" Could not cast an Epetra_Operator to a Epetra_CrsMatrix or a Tpetra_Operator to a "
956 "Tpetra::CrsMatrix\n";
958 *out <<
"*** THROWN EXCEPTION ***\n";
959 *out << e.what() << std::endl;
960 *out <<
"************************\n";
966 const MultiVector getDiagonal(
const LinearOp &op) {
969 auto diagOp = getDiagonalOpEpetra(op);
971 if (!diagOp.second) {
972 diagOp = getDiagonalOpTpetra(op);
974 if (!diagOp.second) {
975 throw std::logic_error(
"Neither Epetra nor Tpetra");
979 Teuchos::RCP<const Thyra::MultiVectorBase<double>> v =
980 Teuchos::rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<double>>(diagOp.first)
982 return Teuchos::rcp_const_cast<Thyra::MultiVectorBase<double>>(v);
983 }
catch (std::exception &e) {
984 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
986 *out <<
"Teko: getDiagonal requires an Epetra_CrsMatrix or a Tpetra::CrsMatrix\n";
987 *out <<
" Could not extract an Epetra_Operator or a Tpetra_Operator from a \""
988 << op->description() << std::endl;
990 *out <<
" Could not cast an Epetra_Operator to a Epetra_CrsMatrix or a Tpetra_Operator to a "
991 "Tpetra::CrsMatrix\n";
993 *out <<
"*** THROWN EXCEPTION ***\n";
994 *out << e.what() << std::endl;
995 *out <<
"************************\n";
1001 const MultiVector getDiagonal(
const Teko::LinearOp &A,
const DiagonalType &dt) {
1002 LinearOp diagOp = Teko::getDiagonalOp(A, dt);
1004 Teuchos::RCP<const Thyra::MultiVectorBase<double>> v =
1005 Teuchos::rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<double>>(diagOp)->getDiag();
1006 return Teuchos::rcp_const_cast<Thyra::MultiVectorBase<double>>(v);
1020 const ModifiableLinearOp getInvDiagonalOp(
const LinearOp &op) {
1022 auto diagonal_op = rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<double>>(op);
1023 if (diagonal_op != Teuchos::null) {
1024 auto diag = diagonal_op->getDiag();
1025 auto inv_diag = diag->clone_v();
1026 Thyra::reciprocal(*diag, inv_diag.ptr());
1027 return rcp(
new Thyra::DefaultDiagonalLinearOp<double>(inv_diag));
1031 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_op =
1032 rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(op);
1033 if (blocked_op != Teuchos::null) {
1034 int numRows = blocked_op->productRange()->numBlocks();
1035 TEUCHOS_ASSERT(blocked_op->productDomain()->numBlocks() == numRows);
1036 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_diag =
1037 Thyra::defaultBlockedLinearOp<double>();
1038 blocked_diag->beginBlockFill(numRows, numRows);
1039 for (
int r = 0; r < numRows; ++r) {
1040 for (
int c = 0; c < numRows; ++c) {
1042 blocked_diag->setNonconstBlock(r, c, getInvDiagonalOp(blocked_op->getBlock(r, c)));
1044 blocked_diag->setBlock(r, c,
1045 Thyra::zero<double>(blocked_op->getBlock(r, c)->range(),
1046 blocked_op->getBlock(r, c)->domain()));
1049 blocked_diag->endBlockFill();
1050 return blocked_diag;
1053 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
1055 bool transp =
false;
1056 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp =
1057 Teko::TpetraHelpers::getTpetraCrsMatrix(op, &scalar, &transp);
1060 const RCP<Tpetra::Vector<ST, LO, GO, NT>> diag =
1061 Tpetra::createVector<ST, LO, GO, NT>(tCrsOp->getRowMap());
1062 diag->scale(scalar);
1063 tCrsOp->getLocalDiagCopy(*diag);
1064 diag->reciprocal(*diag);
1067 return Teko::TpetraHelpers::thyraDiagOp(diag, *tCrsOp->getRowMap(),
1068 "inv(diag( " + op->getObjectLabel() +
" ))");
1071 #ifdef TEKO_HAVE_EPETRA
1072 RCP<const Thyra::EpetraLinearOp> eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op,
true);
1073 RCP<const Epetra_CrsMatrix> eCrsOp =
1074 rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
1077 const RCP<Epetra_Vector> diag = rcp(
new Epetra_Vector(eCrsOp->RowMap()));
1078 TEUCHOS_TEST_FOR_EXCEPT(eCrsOp->ExtractDiagonalCopy(*diag));
1079 diag->Reciprocal(*diag);
1082 return Teko::Epetra::thyraDiagOp(diag, eCrsOp->RowMap(),
1083 "inv(diag( " + op->getObjectLabel() +
" ))");
1085 throw std::logic_error(
1086 "getInvDiagonalOp is trying to use Epetra "
1087 "code, but TEKO_HAVE_EPETRA is disabled!");
1104 const LinearOp explicitMultiply(
const LinearOp &opl,
const LinearOp &opm,
const LinearOp &opr) {
1109 bool isBlockedL = isPhysicallyBlockedLinearOp(opl);
1110 bool isBlockedM = isPhysicallyBlockedLinearOp(opm);
1111 bool isBlockedR = isPhysicallyBlockedLinearOp(opr);
1114 if ((isBlockedL && isBlockedM && isBlockedR)) {
1115 double scalarl = 0.0;
1116 bool transpl =
false;
1117 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1118 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1119 double scalarm = 0.0;
1120 bool transpm =
false;
1121 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opm =
1122 getPhysicallyBlockedLinearOp(opm, &scalarm, &transpm);
1123 double scalarr = 0.0;
1124 bool transpr =
false;
1125 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1126 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1127 double scalar = scalarl * scalarm * scalarr;
1129 int numRows = blocked_opl->productRange()->numBlocks();
1130 int numCols = blocked_opr->productDomain()->numBlocks();
1131 int numMiddle = blocked_opm->productRange()->numBlocks();
1135 TEUCHOS_ASSERT(blocked_opm->productDomain()->numBlocks() == numMiddle);
1136 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1137 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1139 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1140 Thyra::defaultBlockedLinearOp<double>();
1141 blocked_product->beginBlockFill(numRows, numCols);
1142 for (
int r = 0; r < numRows; ++r) {
1143 for (
int c = 0; c < numCols; ++c) {
1144 LinearOp product_rc = explicitMultiply(
1145 blocked_opl->getBlock(r, 0), blocked_opm->getBlock(0, 0), blocked_opr->getBlock(0, c));
1146 for (
int m = 1; m < numMiddle; ++m) {
1147 LinearOp product_m =
1148 explicitMultiply(blocked_opl->getBlock(r, m), blocked_opm->getBlock(m, m),
1149 blocked_opr->getBlock(m, c));
1150 product_rc = explicitAdd(product_rc, product_m);
1152 blocked_product->setBlock(r, c, product_rc);
1155 blocked_product->endBlockFill();
1156 return Thyra::scale<double>(scalar, blocked_product.getConst());
1160 if (isBlockedL && !isBlockedM && isBlockedR) {
1161 double scalarl = 0.0;
1162 bool transpl =
false;
1163 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1164 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1165 double scalarr = 0.0;
1166 bool transpr =
false;
1167 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1168 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1169 double scalar = scalarl * scalarr;
1171 int numRows = blocked_opl->productRange()->numBlocks();
1172 int numCols = blocked_opr->productDomain()->numBlocks();
1176 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1177 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1179 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1180 Thyra::defaultBlockedLinearOp<double>();
1181 blocked_product->beginBlockFill(numRows, numCols);
1182 for (
int r = 0; r < numRows; ++r) {
1183 for (
int c = 0; c < numCols; ++c) {
1184 LinearOp product_rc =
1185 explicitMultiply(blocked_opl->getBlock(r, 0), opm, blocked_opr->getBlock(0, c));
1186 blocked_product->setBlock(r, c, product_rc);
1189 blocked_product->endBlockFill();
1190 return Thyra::scale<double>(scalar, blocked_product.getConst());
1194 if (!isBlockedL && !isBlockedM && isBlockedR) {
1195 double scalarr = 0.0;
1196 bool transpr =
false;
1197 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1198 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1199 double scalar = scalarr;
1202 int numCols = blocked_opr->productDomain()->numBlocks();
1206 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1208 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1209 Thyra::defaultBlockedLinearOp<double>();
1210 blocked_product->beginBlockFill(numRows, numCols);
1211 for (
int c = 0; c < numCols; ++c) {
1212 LinearOp product_c = explicitMultiply(opl, opm, blocked_opr->getBlock(0, c));
1213 blocked_product->setBlock(0, c, product_c);
1215 blocked_product->endBlockFill();
1216 return Thyra::scale<double>(scalar, blocked_product.getConst());
1221 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1222 bool isTpetram = Teko::TpetraHelpers::isTpetraLinearOp(opm);
1223 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1225 if (isTpetral && isTpetram &&
1230 bool transpl =
false;
1231 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1232 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1234 bool transpm =
false;
1235 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpm =
1236 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarm, &transpm);
1238 bool transpr =
false;
1239 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1240 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1243 RCP<Thyra::LinearOpBase<ST>> explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1244 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
1245 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
1248 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOplm =
1249 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1250 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1251 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1252 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOpl, transpl, *tCrsOpm, transpm, *tCrsOplm);
1253 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOplm,
false, *tCrsOpr, transpr,
1255 explicitCrsOp->resumeFill();
1256 explicitCrsOp->scale(scalarl * scalarm * scalarr);
1257 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1258 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1259 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1263 }
else if (isTpetral && !isTpetram && isTpetrar) {
1267 bool transpl =
false;
1268 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1269 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1271 bool transpr =
false;
1272 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1273 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1275 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr;
1278 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpm =
1279 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opm);
1280 if (dOpm != Teuchos::null) {
1281 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1282 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpm->getDiag(),
true);
1283 diagPtr = rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
1287 else if (rcp_dynamic_cast<
const Thyra::ZeroLinearOpBase<ST>>(opm) != Teuchos::null) {
1288 diagPtr = rcp(
new Tpetra::Vector<ST, LO, GO, NT>(tCrsOpl->getDomainMap()));
1290 TEUCHOS_ASSERT(
false);
1292 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOplm =
1293 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1294 tCrsOpl, Tpetra::Import<LO, GO, NT>(tCrsOpl->getRowMap(), tCrsOpl->getRowMap()));
1297 tCrsOplm->rightScale(*diagPtr);
1300 RCP<Thyra::LinearOpBase<ST>> explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1301 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
1302 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
1305 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1306 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1307 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOplm,
false, *tCrsOpr, transpr,
1309 explicitCrsOp->resumeFill();
1310 explicitCrsOp->scale(scalarl * scalarr);
1311 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1312 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1313 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1318 #ifdef TEKO_HAVE_EPETRA
1320 const LinearOp implicitOp = Thyra::multiply(opl, opm, opr);
1323 const RCP<Thyra::LinearOpTransformerBase<double>> prodTrans =
1324 Thyra::epetraExtDiagScaledMatProdTransformer();
1327 const RCP<Thyra::LinearOpBase<double>> explicitOp = prodTrans->createOutputOp();
1328 prodTrans->transform(*implicitOp, explicitOp.ptr());
1329 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" * " +
1330 opm->getObjectLabel() +
" * " + opr->getObjectLabel() +
" )");
1334 throw std::logic_error(
1335 "explicitMultiply is trying to use Epetra "
1336 "code, but TEKO_HAVE_EPETRA is disabled!");
1355 const ModifiableLinearOp explicitMultiply(
const LinearOp &opl,
const LinearOp &opm,
1356 const LinearOp &opr,
const ModifiableLinearOp &destOp) {
1357 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1358 bool isTpetram = Teko::TpetraHelpers::isTpetraLinearOp(opm);
1359 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1361 if (isTpetral && isTpetram &&
1366 bool transpl =
false;
1367 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1368 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1370 bool transpm =
false;
1371 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpm =
1372 Teko::TpetraHelpers::getTpetraCrsMatrix(opm, &scalarm, &transpm);
1374 bool transpr =
false;
1375 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1376 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1379 auto tExplicitOp = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(destOp);
1380 if (tExplicitOp.is_null()) tExplicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1383 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOplm =
1384 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1385 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1386 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1387 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOpl, transpl, *tCrsOpm, transpm, *tCrsOplm);
1388 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOplm,
false, *tCrsOpr, transpr,
1390 explicitCrsOp->resumeFill();
1391 explicitCrsOp->scale(scalarl * scalarm * scalarr);
1392 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1393 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1394 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1398 }
else if (isTpetral && !isTpetram && isTpetrar) {
1402 bool transpl =
false;
1403 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1404 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1406 bool transpr =
false;
1407 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1408 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1411 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpm =
1412 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opm,
true);
1413 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1414 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpm->getDiag(),
true);
1415 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr =
1416 rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
true);
1417 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOplm =
1418 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1419 tCrsOpl, Tpetra::Import<LO, GO, NT>(tCrsOpl->getRowMap(), tCrsOpl->getRowMap()));
1422 tCrsOplm->rightScale(*diagPtr);
1425 RCP<Thyra::LinearOpBase<ST>> explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1426 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
1427 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
1430 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1431 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1432 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOplm,
false, *tCrsOpr, transpr,
1434 explicitCrsOp->resumeFill();
1435 explicitCrsOp->scale(scalarl * scalarr);
1436 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1437 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1438 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1443 #ifdef TEKO_HAVE_EPETRA
1445 const LinearOp implicitOp = Thyra::multiply(opl, opm, opr);
1448 const RCP<Thyra::LinearOpTransformerBase<double>> prodTrans =
1449 Thyra::epetraExtDiagScaledMatProdTransformer();
1452 ModifiableLinearOp explicitOp;
1455 if (destOp == Teuchos::null)
1456 explicitOp = prodTrans->createOutputOp();
1458 explicitOp = destOp;
1461 prodTrans->transform(*implicitOp, explicitOp.ptr());
1464 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" * " +
1465 opm->getObjectLabel() +
" * " + opr->getObjectLabel() +
" )");
1469 throw std::logic_error(
1470 "explicitMultiply is trying to use Epetra "
1471 "code, but TEKO_HAVE_EPETRA is disabled!");
1486 const LinearOp explicitMultiply(
const LinearOp &opl,
const LinearOp &opr) {
1491 bool isBlockedL = isPhysicallyBlockedLinearOp(opl);
1492 bool isBlockedR = isPhysicallyBlockedLinearOp(opr);
1495 if ((isBlockedL && isBlockedR)) {
1496 double scalarl = 0.0;
1497 bool transpl =
false;
1498 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1499 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1500 double scalarr = 0.0;
1501 bool transpr =
false;
1502 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1503 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1504 double scalar = scalarl * scalarr;
1506 int numRows = blocked_opl->productRange()->numBlocks();
1507 int numCols = blocked_opr->productDomain()->numBlocks();
1508 int numMiddle = blocked_opl->productDomain()->numBlocks();
1510 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1512 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1513 Thyra::defaultBlockedLinearOp<double>();
1514 blocked_product->beginBlockFill(numRows, numCols);
1515 for (
int r = 0; r < numRows; ++r) {
1516 for (
int c = 0; c < numCols; ++c) {
1517 LinearOp product_rc =
1518 explicitMultiply(blocked_opl->getBlock(r, 0), blocked_opr->getBlock(0, c));
1519 for (
int m = 1; m < numMiddle; ++m) {
1520 LinearOp product_m =
1521 explicitMultiply(blocked_opl->getBlock(r, m), blocked_opr->getBlock(m, c));
1522 product_rc = explicitAdd(product_rc, product_m);
1524 blocked_product->setBlock(r, c, Thyra::scale(scalar, product_rc));
1527 blocked_product->endBlockFill();
1528 return blocked_product;
1532 if ((isBlockedL && !isBlockedR)) {
1533 double scalarl = 0.0;
1534 bool transpl =
false;
1535 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1536 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1537 double scalar = scalarl;
1539 int numRows = blocked_opl->productRange()->numBlocks();
1543 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1545 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1546 Thyra::defaultBlockedLinearOp<double>();
1547 blocked_product->beginBlockFill(numRows, numCols);
1548 for (
int r = 0; r < numRows; ++r) {
1549 LinearOp product_r = explicitMultiply(blocked_opl->getBlock(r, 0), opr);
1550 blocked_product->setBlock(r, 0, Thyra::scale(scalar, product_r));
1552 blocked_product->endBlockFill();
1553 return blocked_product;
1557 if ((!isBlockedL && isBlockedR)) {
1558 double scalarr = 0.0;
1559 bool transpr =
false;
1560 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1561 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1562 double scalar = scalarr;
1565 int numCols = blocked_opr->productDomain()->numBlocks();
1568 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1570 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1571 Thyra::defaultBlockedLinearOp<double>();
1572 blocked_product->beginBlockFill(numRows, numCols);
1573 for (
int c = 0; c < numCols; ++c) {
1574 LinearOp product_c = explicitMultiply(opl, blocked_opr->getBlock(0, c));
1575 blocked_product->setBlock(0, c, Thyra::scale(scalar, product_c));
1577 blocked_product->endBlockFill();
1578 return blocked_product;
1581 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1582 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1584 if (isTpetral && isTpetrar) {
1587 bool transpl =
false;
1588 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1589 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1591 bool transpr =
false;
1592 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1593 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1596 RCP<Thyra::LinearOpBase<ST>> explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1597 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
1598 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
1601 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1602 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1603 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOpl, transpl, *tCrsOpr, transpr,
1605 explicitCrsOp->resumeFill();
1606 explicitCrsOp->scale(scalarl * scalarr);
1607 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1608 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1609 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1613 }
else if (isTpetral && !isTpetrar) {
1617 bool transpl =
false;
1618 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1619 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1622 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpr =
1623 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opr,
true);
1624 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1625 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpr->getDiag(),
true);
1626 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr =
1627 rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
true);
1628 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1629 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1630 tCrsOpl, Tpetra::Import<LO, GO, NT>(tCrsOpl->getRowMap(), tCrsOpl->getRowMap()));
1632 explicitCrsOp->rightScale(*diagPtr);
1633 explicitCrsOp->resumeFill();
1634 explicitCrsOp->scale(scalarl);
1635 explicitCrsOp->fillComplete(tCrsOpl->getDomainMap(), tCrsOpl->getRangeMap());
1637 return Thyra::constTpetraLinearOp<ST, LO, GO, NT>(
1638 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1639 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()), explicitCrsOp);
1641 }
else if (!isTpetral && isTpetrar) {
1645 bool transpr =
false;
1646 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1647 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1649 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr;
1652 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpl =
1653 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opl);
1654 if (dOpl != Teuchos::null) {
1655 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1656 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpl->getDiag(),
true);
1657 diagPtr = rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
1661 else if (rcp_dynamic_cast<
const Thyra::ZeroLinearOpBase<ST>>(opl) != Teuchos::null) {
1662 diagPtr = rcp(
new Tpetra::Vector<ST, LO, GO, NT>(tCrsOpr->getRangeMap()));
1664 TEUCHOS_ASSERT(
false);
1666 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1667 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1668 tCrsOpr, Tpetra::Import<LO, GO, NT>(tCrsOpr->getRowMap(), tCrsOpr->getRowMap()));
1670 explicitCrsOp->leftScale(*diagPtr);
1671 explicitCrsOp->resumeFill();
1672 explicitCrsOp->scale(scalarr);
1673 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpr->getRangeMap());
1675 return Thyra::constTpetraLinearOp<ST, LO, GO, NT>(
1676 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1677 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()), explicitCrsOp);
1680 #ifdef TEKO_HAVE_EPETRA
1682 const LinearOp implicitOp = Thyra::multiply(opl, opr);
1685 RCP<Thyra::LinearOpTransformerBase<double>> prodTrans =
1686 Thyra::epetraExtDiagScalingTransformer();
1690 if (not prodTrans->isCompatible(*implicitOp))
1691 prodTrans = Thyra::epetraExtDiagScaledMatProdTransformer();
1694 const RCP<Thyra::LinearOpBase<double>> explicitOp = prodTrans->createOutputOp();
1695 prodTrans->transform(*implicitOp, explicitOp.ptr());
1696 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" * " +
1697 opr->getObjectLabel() +
" )");
1701 throw std::logic_error(
1702 "explicitMultiply is trying to use Epetra "
1703 "code, but TEKO_HAVE_EPETRA is disabled!");
1721 const ModifiableLinearOp explicitMultiply(
const LinearOp &opl,
const LinearOp &opr,
1722 const ModifiableLinearOp &destOp) {
1727 bool isBlockedL = isPhysicallyBlockedLinearOp(opl);
1728 bool isBlockedR = isPhysicallyBlockedLinearOp(opr);
1731 if ((isBlockedL && isBlockedR)) {
1732 double scalarl = 0.0;
1733 bool transpl =
false;
1734 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1735 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1736 double scalarr = 0.0;
1737 bool transpr =
false;
1738 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1739 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1740 double scalar = scalarl * scalarr;
1742 int numRows = blocked_opl->productRange()->numBlocks();
1743 int numCols = blocked_opr->productDomain()->numBlocks();
1744 int numMiddle = blocked_opl->productDomain()->numBlocks();
1746 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1748 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1749 Thyra::defaultBlockedLinearOp<double>();
1750 blocked_product->beginBlockFill(numRows, numCols);
1751 for (
int r = 0; r < numRows; ++r) {
1752 for (
int c = 0; c < numCols; ++c) {
1753 LinearOp product_rc =
1754 explicitMultiply(blocked_opl->getBlock(r, 0), blocked_opr->getBlock(0, c));
1755 for (
int m = 1; m < numMiddle; ++m) {
1756 LinearOp product_m =
1757 explicitMultiply(blocked_opl->getBlock(r, m), blocked_opr->getBlock(m, c));
1758 product_rc = explicitAdd(product_rc, product_m);
1760 blocked_product->setBlock(r, c, Thyra::scale(scalar, product_rc));
1763 blocked_product->endBlockFill();
1764 return blocked_product;
1768 if ((isBlockedL && !isBlockedR)) {
1769 double scalarl = 0.0;
1770 bool transpl =
false;
1771 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1772 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1773 double scalar = scalarl;
1775 int numRows = blocked_opl->productRange()->numBlocks();
1779 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1781 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1782 Thyra::defaultBlockedLinearOp<double>();
1783 blocked_product->beginBlockFill(numRows, numCols);
1784 for (
int r = 0; r < numRows; ++r) {
1785 LinearOp product_r = explicitMultiply(blocked_opl->getBlock(r, 0), opr);
1786 blocked_product->setBlock(r, 0, Thyra::scale(scalar, product_r));
1788 blocked_product->endBlockFill();
1789 return blocked_product;
1793 if ((!isBlockedL && isBlockedR)) {
1794 double scalarr = 0.0;
1795 bool transpr =
false;
1796 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1797 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1798 double scalar = scalarr;
1801 int numCols = blocked_opr->productDomain()->numBlocks();
1804 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1806 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1807 Thyra::defaultBlockedLinearOp<double>();
1808 blocked_product->beginBlockFill(numRows, numCols);
1809 for (
int c = 0; c < numCols; ++c) {
1810 LinearOp product_c = explicitMultiply(opl, blocked_opr->getBlock(0, c));
1811 blocked_product->setBlock(0, c, Thyra::scale(scalar, product_c));
1813 blocked_product->endBlockFill();
1814 return blocked_product;
1817 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1818 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1820 if (isTpetral && isTpetrar) {
1825 bool transpl =
false;
1826 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1827 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1829 bool transpr =
false;
1830 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1831 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1834 RCP<Thyra::LinearOpBase<ST>> explicitOp;
1835 if (destOp != Teuchos::null)
1836 explicitOp = destOp;
1838 explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1839 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
1840 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
1843 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1844 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1845 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOpl, transpl, *tCrsOpr, transpr,
1847 explicitCrsOp->resumeFill();
1848 explicitCrsOp->scale(scalarl * scalarr);
1849 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1850 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1851 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1855 }
else if (isTpetral && !isTpetrar) {
1859 bool transpl =
false;
1860 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1861 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1864 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpr =
1865 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opr);
1866 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1867 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpr->getDiag(),
true);
1868 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr =
1869 rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
true);
1872 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1873 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1874 tCrsOpl, Tpetra::Import<LO, GO, NT>(tCrsOpl->getRowMap(), tCrsOpl->getRowMap()));
1875 explicitCrsOp->rightScale(*diagPtr);
1876 explicitCrsOp->resumeFill();
1877 explicitCrsOp->scale(scalarl);
1878 explicitCrsOp->fillComplete(tCrsOpl->getDomainMap(), tCrsOpl->getRangeMap());
1879 return Thyra::tpetraLinearOp<ST, LO, GO, NT>(
1880 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1881 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()), explicitCrsOp);
1883 }
else if (!isTpetral && isTpetrar) {
1887 bool transpr =
false;
1888 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1889 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1892 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpl =
1893 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opl,
true);
1894 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1895 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpl->getDiag(),
true);
1896 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr =
1897 rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
true);
1900 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1901 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1902 tCrsOpr, Tpetra::Import<LO, GO, NT>(tCrsOpr->getRowMap(), tCrsOpr->getRowMap()));
1903 explicitCrsOp->leftScale(*diagPtr);
1904 explicitCrsOp->resumeFill();
1905 explicitCrsOp->scale(scalarr);
1906 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpr->getRangeMap());
1907 return Thyra::tpetraLinearOp<ST, LO, GO, NT>(
1908 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1909 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()), explicitCrsOp);
1912 #ifdef TEKO_HAVE_EPETRA
1914 const LinearOp implicitOp = Thyra::multiply(opl, opr);
1918 RCP<Thyra::LinearOpTransformerBase<double>> prodTrans =
1919 Thyra::epetraExtDiagScalingTransformer();
1923 if (not prodTrans->isCompatible(*implicitOp))
1924 prodTrans = Thyra::epetraExtDiagScaledMatProdTransformer();
1927 ModifiableLinearOp explicitOp;
1930 if (destOp == Teuchos::null)
1931 explicitOp = prodTrans->createOutputOp();
1933 explicitOp = destOp;
1936 prodTrans->transform(*implicitOp, explicitOp.ptr());
1939 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" * " +
1940 opr->getObjectLabel() +
" )");
1944 throw std::logic_error(
1945 "explicitMultiply is trying to use Epetra "
1946 "code, but TEKO_HAVE_EPETRA is disabled!");
1961 const LinearOp explicitAdd(
const LinearOp &opl_in,
const LinearOp &opr_in) {
1963 if (isPhysicallyBlockedLinearOp(opl_in) && isPhysicallyBlockedLinearOp(opr_in)) {
1964 double scalarl = 0.0;
1965 bool transpl =
false;
1966 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1967 getPhysicallyBlockedLinearOp(opl_in, &scalarl, &transpl);
1969 double scalarr = 0.0;
1970 bool transpr =
false;
1971 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1972 getPhysicallyBlockedLinearOp(opr_in, &scalarr, &transpr);
1974 int numRows = blocked_opl->productRange()->numBlocks();
1975 int numCols = blocked_opl->productDomain()->numBlocks();
1976 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numRows);
1977 TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == numCols);
1979 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_sum =
1980 Thyra::defaultBlockedLinearOp<double>();
1981 blocked_sum->beginBlockFill(numRows, numCols);
1982 for (
int r = 0; r < numRows; ++r)
1983 for (
int c = 0; c < numCols; ++c)
1984 blocked_sum->setBlock(r, c,
1985 explicitAdd(Thyra::scale(scalarl, blocked_opl->getBlock(r, c)),
1986 Thyra::scale(scalarr, blocked_opr->getBlock(r, c))));
1987 blocked_sum->endBlockFill();
1992 LinearOp opl = opl_in;
1993 LinearOp opr = opr_in;
1994 if (isPhysicallyBlockedLinearOp(opl_in)) {
1995 double scalarl = 0.0;
1996 bool transpl =
false;
1997 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1998 getPhysicallyBlockedLinearOp(opl_in, &scalarl, &transpl);
1999 TEUCHOS_ASSERT(blocked_opl->productRange()->numBlocks() == 1);
2000 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == 1);
2001 opl = Thyra::scale(scalarl, blocked_opl->getBlock(0, 0));
2003 if (isPhysicallyBlockedLinearOp(opr_in)) {
2004 double scalarr = 0.0;
2005 bool transpr =
false;
2006 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
2007 getPhysicallyBlockedLinearOp(opr_in, &scalarr, &transpr);
2008 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == 1);
2009 TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == 1);
2010 opr = Thyra::scale(scalarr, blocked_opr->getBlock(0, 0));
2013 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
2014 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
2017 if (isZeroOp(opl)) {
2018 if (isZeroOp(opr))
return opr;
2021 bool transp =
false;
2022 auto crs_op = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalar, &transp);
2023 auto zero_crs = Tpetra::createCrsMatrix<ST, LO, GO, NT>(crs_op->getRowMap());
2024 zero_crs->fillComplete();
2025 opl = Thyra::constTpetraLinearOp<ST, LO, GO, NT>(
2026 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(crs_op->getRangeMap()),
2027 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(crs_op->getDomainMap()), zero_crs);
2030 return opr->clone();
2032 if (isZeroOp(opr)) {
2035 bool transp =
false;
2036 auto crs_op = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalar, &transp);
2037 auto zero_crs = Tpetra::createCrsMatrix<ST, LO, GO, NT>(crs_op->getRowMap());
2038 zero_crs->fillComplete();
2039 opr = Thyra::constTpetraLinearOp<ST, LO, GO, NT>(
2040 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(crs_op->getRangeMap()),
2041 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(crs_op->getDomainMap()), zero_crs);
2044 return opl->clone();
2047 if (isTpetral && isTpetrar) {
2052 bool transpl =
false;
2053 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
2054 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
2056 bool transpr =
false;
2057 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
2058 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
2061 RCP<Thyra::LinearOpBase<ST>> explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
2062 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
2063 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
2066 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
2067 Tpetra::MatrixMatrix::add<ST, LO, GO, NT>(scalarl, transpl, *tCrsOpl, scalarr, transpr,
2069 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
2070 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
2075 #ifdef TEKO_HAVE_EPETRA
2077 const LinearOp implicitOp = Thyra::add(opl, opr);
2080 const RCP<Thyra::LinearOpTransformerBase<double>> prodTrans = Thyra::epetraExtAddTransformer();
2083 const RCP<Thyra::LinearOpBase<double>> explicitOp = prodTrans->createOutputOp();
2084 prodTrans->transform(*implicitOp, explicitOp.ptr());
2085 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" + " +
2086 opr->getObjectLabel() +
" )");
2090 throw std::logic_error(
2091 "explicitAdd is trying to use Epetra "
2092 "code, but TEKO_HAVE_EPETRA is disabled!");
2109 const ModifiableLinearOp explicitAdd(
const LinearOp &opl_in,
const LinearOp &opr_in,
2110 const ModifiableLinearOp &destOp) {
2112 if (isPhysicallyBlockedLinearOp(opl_in) && isPhysicallyBlockedLinearOp(opr_in)) {
2113 double scalarl = 0.0;
2114 bool transpl =
false;
2115 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
2116 getPhysicallyBlockedLinearOp(opl_in, &scalarl, &transpl);
2118 double scalarr = 0.0;
2119 bool transpr =
false;
2120 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
2121 getPhysicallyBlockedLinearOp(opr_in, &scalarr, &transpr);
2123 int numRows = blocked_opl->productRange()->numBlocks();
2124 int numCols = blocked_opl->productDomain()->numBlocks();
2125 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numRows);
2126 TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == numCols);
2128 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_sum =
2129 Teuchos::rcp_dynamic_cast<Thyra::DefaultBlockedLinearOp<double>>(destOp);
2130 if (blocked_sum.is_null()) {
2132 blocked_sum = Thyra::defaultBlockedLinearOp<double>();
2134 blocked_sum->beginBlockFill(numRows, numCols);
2135 for (
int r = 0; r < numRows; ++r) {
2136 for (
int c = 0; c < numCols; ++c) {
2138 explicitAdd(Thyra::scale(scalarl, blocked_opl->getBlock(r, c)),
2139 Thyra::scale(scalarr, blocked_opr->getBlock(r, c)), Teuchos::null);
2140 blocked_sum->setNonconstBlock(r, c, block);
2143 blocked_sum->endBlockFill();
2147 for (
int r = 0; r < numRows; ++r)
2148 for (
int c = 0; c < numCols; ++c)
2149 explicitAdd(Thyra::scale(scalarl, blocked_opl->getBlock(r, c)),
2150 Thyra::scale(scalarr, blocked_opr->getBlock(r, c)),
2151 blocked_sum->getNonconstBlock(r, c));
2157 LinearOp opl = opl_in;
2158 LinearOp opr = opr_in;
2160 if (isPhysicallyBlockedLinearOp(opl)) {
2161 double scalarl = 0.0;
2162 bool transpl =
false;
2163 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
2164 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
2165 TEUCHOS_ASSERT(blocked_opl->productRange()->numBlocks() == 1);
2166 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == 1);
2167 opl = Thyra::scale(scalarl, blocked_opl->getBlock(0, 0));
2169 if (isPhysicallyBlockedLinearOp(opr)) {
2170 double scalarr = 0.0;
2171 bool transpr =
false;
2172 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
2173 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
2174 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == 1);
2175 TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == 1);
2176 opr = Thyra::scale(scalarr, blocked_opr->getBlock(0, 0));
2179 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
2180 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
2182 if (isTpetral && isTpetrar) {
2187 bool transpl =
false;
2188 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
2189 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
2191 bool transpr =
false;
2192 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
2193 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
2196 RCP<Thyra::LinearOpBase<ST>> explicitOp;
2197 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp;
2198 if (!destOp.is_null()) {
2199 explicitOp = destOp;
2200 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tOp =
2201 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(destOp);
2204 rcp_dynamic_cast<Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getTpetraOperator());
2205 bool needNewTpetraMatrix =
2206 (explicitCrsOp.is_null()) || (tCrsOpl == explicitCrsOp) || (tCrsOpr == explicitCrsOp);
2207 if (!needNewTpetraMatrix) {
2210 Tpetra::MatrixMatrix::Add<ST, LO, GO, NT>(*tCrsOpl, transpl, scalarl, *tCrsOpr, transpr,
2211 scalarr, explicitCrsOp);
2212 }
catch (std::logic_error &e) {
2213 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
2214 *out <<
"*** THROWN EXCEPTION ***\n";
2215 *out << e.what() << std::endl;
2216 *out <<
"************************\n";
2217 *out <<
"Teko: explicitAdd unable to reuse existing operator. Creating new operator.\n"
2219 needNewTpetraMatrix =
true;
2222 if (needNewTpetraMatrix)
2224 explicitCrsOp = Tpetra::MatrixMatrix::add<ST, LO, GO, NT>(scalarl, transpl, *tCrsOpl,
2225 scalarr, transpr, *tCrsOpr);
2227 explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
2229 explicitCrsOp = Tpetra::MatrixMatrix::add<ST, LO, GO, NT>(scalarl, transpl, *tCrsOpl, scalarr,
2232 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
2233 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
2235 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
2236 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
2241 #ifdef TEKO_HAVE_EPETRA
2243 const LinearOp implicitOp = Thyra::add(opl, opr);
2246 const RCP<Thyra::LinearOpTransformerBase<double>> prodTrans = Thyra::epetraExtAddTransformer();
2249 RCP<Thyra::LinearOpBase<double>> explicitOp;
2250 if (destOp != Teuchos::null)
2251 explicitOp = destOp;
2253 explicitOp = prodTrans->createOutputOp();
2256 prodTrans->transform(*implicitOp, explicitOp.ptr());
2257 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" + " +
2258 opr->getObjectLabel() +
" )");
2262 throw std::logic_error(
2263 "explicitAdd is trying to use Epetra "
2264 "code, but TEKO_HAVE_EPETRA is disabled!");
2273 const ModifiableLinearOp explicitSum(
const LinearOp &op,
const ModifiableLinearOp &destOp) {
2274 #ifdef TEKO_HAVE_EPETRA
2276 const RCP<const Epetra_CrsMatrix> epetraOp =
2277 rcp_dynamic_cast<
const Epetra_CrsMatrix>(get_Epetra_Operator(*op),
true);
2279 if (destOp == Teuchos::null) {
2280 Teuchos::RCP<Epetra_Operator> epetraDest = Teuchos::rcp(
new Epetra_CrsMatrix(*epetraOp));
2282 return Thyra::nonconstEpetraLinearOp(epetraDest);
2285 const RCP<Epetra_CrsMatrix> epetraDest =
2286 rcp_dynamic_cast<Epetra_CrsMatrix>(get_Epetra_Operator(*destOp),
true);
2288 EpetraExt::MatrixMatrix::Add(*epetraOp,
false, 1.0, *epetraDest, 1.0);
2292 throw std::logic_error(
2293 "explicitSum is trying to use Epetra "
2294 "code, but TEKO_HAVE_EPETRA is disabled!");
2298 const LinearOp explicitTranspose(
const LinearOp &op) {
2299 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2300 RCP<const Thyra::TpetraLinearOp<ST, LO, GO, NT>> tOp =
2301 rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op,
true);
2302 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp =
2303 rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
2306 Tpetra::RowMatrixTransposer<ST, LO, GO, NT> transposer(tCrsOp);
2307 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> transOp = transposer.createTranspose();
2309 return Thyra::tpetraLinearOp<ST, LO, GO, NT>(
2310 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(transOp->getRangeMap()),
2311 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(transOp->getDomainMap()), transOp);
2314 #ifdef TEKO_HAVE_EPETRA
2315 RCP<const Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
2316 TEUCHOS_TEST_FOR_EXCEPTION(eOp == Teuchos::null, std::logic_error,
2317 "Teko::explicitTranspose Not an Epetra_Operator");
2318 RCP<const Epetra_RowMatrix> eRowMatrixOp =
2319 Teuchos::rcp_dynamic_cast<
const Epetra_RowMatrix>(eOp);
2320 TEUCHOS_TEST_FOR_EXCEPTION(eRowMatrixOp == Teuchos::null, std::logic_error,
2321 "Teko::explicitTranspose Not an Epetra_RowMatrix");
2324 EpetraExt::RowMatrix_Transpose tranposeOp;
2325 Epetra_RowMatrix &eMat = tranposeOp(const_cast<Epetra_RowMatrix &>(*eRowMatrixOp));
2329 Teuchos::RCP<Epetra_CrsMatrix> crsMat =
2330 Teuchos::rcp(
new Epetra_CrsMatrix(dynamic_cast<Epetra_CrsMatrix &>(eMat)));
2332 return Thyra::epetraLinearOp(crsMat);
2334 throw std::logic_error(
2335 "explicitTranspose is trying to use Epetra "
2336 "code, but TEKO_HAVE_EPETRA is disabled!");
2341 const LinearOp explicitScale(
double scalar,
const LinearOp &op) {
2342 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2343 RCP<const Thyra::TpetraLinearOp<ST, LO, GO, NT>> tOp =
2344 rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op,
true);
2345 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp =
2346 rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
2348 auto crsOpNew = rcp(
new Tpetra::CrsMatrix<ST, LO, GO, NT>(*tCrsOp, Teuchos::Copy));
2349 crsOpNew->scale(scalar);
2350 return Thyra::tpetraLinearOp<ST, LO, GO, NT>(
2351 Thyra::createVectorSpace<ST, LO, GO, NT>(crsOpNew->getRangeMap()),
2352 Thyra::createVectorSpace<ST, LO, GO, NT>(crsOpNew->getDomainMap()), crsOpNew);
2354 #ifdef TEKO_HAVE_EPETRA
2355 RCP<const Thyra::EpetraLinearOp> eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op,
true);
2356 RCP<const Epetra_CrsMatrix> eCrsOp =
2357 rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
2358 Teuchos::RCP<Epetra_CrsMatrix> crsMat = Teuchos::rcp(
new Epetra_CrsMatrix(*eCrsOp));
2360 crsMat->Scale(scalar);
2362 return Thyra::epetraLinearOp(crsMat);
2364 throw std::logic_error(
2365 "explicitScale is trying to use Epetra "
2366 "code, but TEKO_HAVE_EPETRA is disabled!");
2371 double frobeniusNorm(
const LinearOp &op_in) {
2373 double scalar = 1.0;
2376 if (isPhysicallyBlockedLinearOp(op_in)) {
2377 bool transp =
false;
2378 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_op =
2379 getPhysicallyBlockedLinearOp(op_in, &scalar, &transp);
2380 TEUCHOS_ASSERT(blocked_op->productRange()->numBlocks() == 1);
2381 TEUCHOS_ASSERT(blocked_op->productDomain()->numBlocks() == 1);
2382 op = blocked_op->getBlock(0, 0);
2386 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2387 const RCP<const Thyra::TpetraLinearOp<ST, LO, GO, NT>> tOp =
2388 rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op);
2389 const RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> crsOp =
2390 rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
2392 return crsOp->getFrobeniusNorm();
2394 #ifdef TEKO_HAVE_EPETRA
2395 const RCP<const Epetra_Operator> epOp = Thyra::get_Epetra_Operator(*op);
2396 const RCP<const Epetra_CrsMatrix> crsOp = rcp_dynamic_cast<
const Epetra_CrsMatrix>(epOp,
true);
2397 return crsOp->NormFrobenius();
2399 throw std::logic_error(
2400 "frobeniusNorm is trying to use Epetra "
2401 "code, but TEKO_HAVE_EPETRA is disabled!");
2406 double oneNorm(
const LinearOp &op) {
2407 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2408 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::logic_error,
2409 "One norm not currently implemented for Tpetra matrices");
2412 #ifdef TEKO_HAVE_EPETRA
2413 const RCP<const Epetra_Operator> epOp = Thyra::get_Epetra_Operator(*op);
2414 const RCP<const Epetra_CrsMatrix> crsOp = rcp_dynamic_cast<
const Epetra_CrsMatrix>(epOp,
true);
2415 return crsOp->NormOne();
2417 throw std::logic_error(
2418 "oneNorm is trying to use Epetra "
2419 "code, but TEKO_HAVE_EPETRA is disabled!");
2424 double infNorm(
const LinearOp &op) {
2425 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2427 bool transp =
false;
2428 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp =
2429 Teko::TpetraHelpers::getTpetraCrsMatrix(op, &scalar, &transp);
2432 const RCP<Tpetra::Vector<ST, LO, GO, NT>> ptrDiag =
2433 Tpetra::createVector<ST, LO, GO, NT>(tCrsOp->getRowMap());
2434 Tpetra::Vector<ST, LO, GO, NT> &diag = *ptrDiag;
2437 diag.putScalar(0.0);
2438 for (LO i = 0; i < (LO)tCrsOp->getLocalNumRows(); i++) {
2439 LO numEntries = tCrsOp->getNumEntriesInLocalRow(i);
2440 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::local_inds_host_view_type indices;
2441 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::values_host_view_type values;
2442 tCrsOp->getLocalRowView(i, indices, values);
2445 for (LO j = 0; j < numEntries; j++) diag.sumIntoLocalValue(i, std::abs(values(j)));
2447 return diag.normInf() * scalar;
2450 #ifdef TEKO_HAVE_EPETRA
2451 const RCP<const Epetra_Operator> epOp = Thyra::get_Epetra_Operator(*op);
2452 const RCP<const Epetra_CrsMatrix> crsOp = rcp_dynamic_cast<
const Epetra_CrsMatrix>(epOp,
true);
2453 return crsOp->NormInf();
2455 throw std::logic_error(
2456 "infNorm is trying to use Epetra "
2457 "code, but TEKO_HAVE_EPETRA is disabled!");
2462 const LinearOp buildDiagonal(
const MultiVector &src,
const std::string &lbl) {
2463 RCP<Thyra::VectorBase<double>> dst = Thyra::createMember(src->range());
2464 Thyra::copy(*src->col(0), dst.ptr());
2466 return Thyra::diagonal<double>(dst, lbl);
2469 const LinearOp buildInvDiagonal(
const MultiVector &src,
const std::string &lbl) {
2470 const RCP<const Thyra::VectorBase<double>> srcV = src->col(0);
2471 RCP<Thyra::VectorBase<double>> dst = Thyra::createMember(srcV->range());
2472 Thyra::reciprocal<double>(*srcV, dst.ptr());
2474 return Thyra::diagonal<double>(dst, lbl);
2478 BlockedMultiVector buildBlockedMultiVector(
const std::vector<MultiVector> &mvv) {
2479 Teuchos::Array<MultiVector> mvA;
2480 Teuchos::Array<VectorSpace> vsA;
2483 std::vector<MultiVector>::const_iterator itr;
2484 for (itr = mvv.begin(); itr != mvv.end(); ++itr) {
2485 mvA.push_back(*itr);
2486 vsA.push_back((*itr)->range());
2490 const RCP<const Thyra::DefaultProductVectorSpace<double>> vs =
2491 Thyra::productVectorSpace<double>(vsA);
2493 return Thyra::defaultProductMultiVector<double>(vs, mvA);
2506 Teuchos::RCP<Thyra::VectorBase<double>> indicatorVector(
const std::vector<int> &indices,
2507 const VectorSpace &vs,
double onValue,
2514 RCP<Thyra::VectorBase<double>> v = Thyra::createMember<double>(vs);
2515 Thyra::put_scalar<double>(offValue, v.ptr());
2518 for (std::size_t i = 0; i < indices.size(); i++)
2519 Thyra::set_ele<double>(indices[i], onValue, v.ptr());
2548 double computeSpectralRad(
const RCP<
const Thyra::LinearOpBase<double>> &A,
double tol,
2549 bool isHermitian,
int numBlocks,
int restart,
int verbosity) {
2550 typedef Thyra::LinearOpBase<double> OP;
2551 typedef Thyra::MultiVectorBase<double> MV;
2553 int startVectors = 1;
2556 const RCP<MV> ivec = Thyra::createMember(A->domain());
2557 Thyra::randomize(-1.0, 1.0, ivec.ptr());
2559 RCP<Anasazi::BasicEigenproblem<double, MV, OP>> eigProb =
2560 rcp(
new Anasazi::BasicEigenproblem<double, MV, OP>(A, ivec));
2562 eigProb->setHermitian(isHermitian);
2565 if (not eigProb->setProblem()) {
2567 return Teuchos::ScalarTraits<double>::nan();
2571 std::string which(
"LM");
2575 Teuchos::ParameterList MyPL;
2576 MyPL.set(
"Verbosity", verbosity);
2577 MyPL.set(
"Which", which);
2578 MyPL.set(
"Block Size", startVectors);
2579 MyPL.set(
"Num Blocks", numBlocks);
2580 MyPL.set(
"Maximum Restarts", restart);
2581 MyPL.set(
"Convergence Tolerance", tol);
2589 Anasazi::BlockKrylovSchurSolMgr<double, MV, OP> MyBlockKrylovSchur(eigProb, MyPL);
2592 Anasazi::ReturnType solverreturn = MyBlockKrylovSchur.solve();
2594 if (solverreturn == Anasazi::Unconverged) {
2595 double real = MyBlockKrylovSchur.getRitzValues().begin()->realpart;
2596 double comp = MyBlockKrylovSchur.getRitzValues().begin()->imagpart;
2598 return -std::abs(std::sqrt(real * real + comp * comp));
2603 double real = eigProb->getSolution().Evals.begin()->realpart;
2604 double comp = eigProb->getSolution().Evals.begin()->imagpart;
2606 return std::abs(std::sqrt(real * real + comp * comp));
2636 double computeSmallestMagEig(
const RCP<
const Thyra::LinearOpBase<double>> &A,
double tol,
2637 bool isHermitian,
int numBlocks,
int restart,
int verbosity) {
2638 typedef Thyra::LinearOpBase<double> OP;
2639 typedef Thyra::MultiVectorBase<double> MV;
2641 int startVectors = 1;
2644 const RCP<MV> ivec = Thyra::createMember(A->domain());
2645 Thyra::randomize(-1.0, 1.0, ivec.ptr());
2647 RCP<Anasazi::BasicEigenproblem<double, MV, OP>> eigProb =
2648 rcp(
new Anasazi::BasicEigenproblem<double, MV, OP>(A, ivec));
2650 eigProb->setHermitian(isHermitian);
2653 if (not eigProb->setProblem()) {
2655 return Teuchos::ScalarTraits<double>::nan();
2659 std::string which(
"SM");
2662 Teuchos::ParameterList MyPL;
2663 MyPL.set(
"Verbosity", verbosity);
2664 MyPL.set(
"Which", which);
2665 MyPL.set(
"Block Size", startVectors);
2666 MyPL.set(
"Num Blocks", numBlocks);
2667 MyPL.set(
"Maximum Restarts", restart);
2668 MyPL.set(
"Convergence Tolerance", tol);
2676 Anasazi::BlockKrylovSchurSolMgr<double, MV, OP> MyBlockKrylovSchur(eigProb, MyPL);
2679 Anasazi::ReturnType solverreturn = MyBlockKrylovSchur.solve();
2681 if (solverreturn == Anasazi::Unconverged) {
2683 return -std::abs(MyBlockKrylovSchur.getRitzValues().begin()->realpart);
2686 return std::abs(eigProb->getSolution().Evals.begin()->realpart);
2698 ModifiableLinearOp getDiagonalOp(
const Teko::LinearOp &A,
const DiagonalType &dt) {
2700 case Diagonal:
return getDiagonalOp(A);
2701 case Lumped:
return getLumpedMatrix(A);
2702 case AbsRowSum:
return getAbsRowSumMatrix(A);
2704 default: TEUCHOS_TEST_FOR_EXCEPT(
true);
2707 return Teuchos::null;
2718 ModifiableLinearOp getInvDiagonalOp(
const Teko::LinearOp &A,
const Teko::DiagonalType &dt) {
2720 case Diagonal:
return getInvDiagonalOp(A);
2721 case Lumped:
return getInvLumpedMatrix(A);
2722 case AbsRowSum:
return getAbsRowSumInvMatrix(A);
2724 default: TEUCHOS_TEST_FOR_EXCEPT(
true);
2727 return Teuchos::null;
2736 std::string getDiagonalName(
const DiagonalType &dt) {
2738 case Diagonal:
return "Diagonal";
2739 case Lumped:
return "Lumped";
2740 case AbsRowSum:
return "AbsRowSum";
2741 case NotDiag:
return "NotDiag";
2742 case BlkDiag:
return "BlkDiag";
2756 DiagonalType getDiagonalType(std::string name) {
2757 if (name ==
"Diagonal")
return Diagonal;
2758 if (name ==
"Lumped")
return Lumped;
2759 if (name ==
"AbsRowSum")
return AbsRowSum;
2760 if (name ==
"BlkDiag")
return BlkDiag;
2765 #ifdef TEKO_HAVE_EPETRA
2766 LinearOp probe(Teuchos::RCP<const Epetra_CrsGraph> &G,
const LinearOp &Op) {
2767 #ifdef Teko_ENABLE_Isorropia
2768 Teuchos::ParameterList probeList;
2769 Prober prober(G, probeList,
true);
2770 Teuchos::RCP<Epetra_CrsMatrix> Mat = rcp(
new Epetra_CrsMatrix(Copy, *G));
2772 prober.probe(Mwrap, *Mat);
2773 return Thyra::epetraLinearOp(Mat);
2777 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::runtime_error,
"Probe requires Isorropia");
2782 double norm_1(
const MultiVector &v, std::size_t col) {
2783 Teuchos::Array<double> n(v->domain()->dim());
2784 Thyra::norms_1<double>(*v, n);
2789 double norm_2(
const MultiVector &v, std::size_t col) {
2790 Teuchos::Array<double> n(v->domain()->dim());
2791 Thyra::norms_2<double>(*v, n);
2796 #ifdef TEKO_HAVE_EPETRA
2797 void putScalar(
const ModifiableLinearOp &op,
double scalar) {
2800 RCP<Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
2803 RCP<Epetra_CrsMatrix> eCrsOp = rcp_dynamic_cast<Epetra_CrsMatrix>(eOp,
true);
2805 eCrsOp->PutScalar(scalar);
2806 }
catch (std::exception &e) {
2807 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
2809 *out <<
"Teko: putScalar requires an Epetra_CrsMatrix\n";
2810 *out <<
" Could not extract an Epetra_Operator from a \"" << op->description() << std::endl;
2812 *out <<
" Could not cast an Epetra_Operator to a Epetra_CrsMatrix\n";
2814 *out <<
"*** THROWN EXCEPTION ***\n";
2815 *out << e.what() << std::endl;
2816 *out <<
"************************\n";
2823 void clipLower(MultiVector &v,
double lowerBound) {
2825 using Teuchos::rcp_dynamic_cast;
2831 for (Thyra::Ordinal i = 0; i < v->domain()->dim(); i++) {
2832 RCP<Thyra::SpmdVectorBase<double>> spmdVec =
2833 rcp_dynamic_cast<Thyra::SpmdVectorBase<double>>(v->col(i),
true);
2835 Teuchos::ArrayRCP<double> values;
2837 spmdVec->getNonconstLocalData(Teuchos::ptrFromRef(values));
2838 for (Teuchos::ArrayRCP<double>::size_type j = 0; j < values.size(); j++) {
2839 if (values[j] < lowerBound) values[j] = lowerBound;
2844 void clipUpper(MultiVector &v,
double upperBound) {
2846 using Teuchos::rcp_dynamic_cast;
2851 for (Thyra::Ordinal i = 0; i < v->domain()->dim(); i++) {
2852 RCP<Thyra::SpmdVectorBase<double>> spmdVec =
2853 rcp_dynamic_cast<Thyra::SpmdVectorBase<double>>(v->col(i),
true);
2855 Teuchos::ArrayRCP<double> values;
2857 spmdVec->getNonconstLocalData(Teuchos::ptrFromRef(values));
2858 for (Teuchos::ArrayRCP<double>::size_type j = 0; j < values.size(); j++) {
2859 if (values[j] > upperBound) values[j] = upperBound;
2864 void replaceValue(MultiVector &v,
double currentValue,
double newValue) {
2866 using Teuchos::rcp_dynamic_cast;
2871 for (Thyra::Ordinal i = 0; i < v->domain()->dim(); i++) {
2872 RCP<Thyra::SpmdVectorBase<double>> spmdVec =
2873 rcp_dynamic_cast<Thyra::SpmdVectorBase<double>>(v->col(i),
true);
2875 Teuchos::ArrayRCP<double> values;
2877 spmdVec->getNonconstLocalData(Teuchos::ptrFromRef(values));
2878 for (Teuchos::ArrayRCP<double>::size_type j = 0; j < values.size(); j++) {
2879 if (values[j] == currentValue) values[j] = newValue;
2884 void columnAverages(
const MultiVector &v, std::vector<double> &averages) {
2885 averages.resize(v->domain()->dim());
2888 Thyra::sums<double>(*v, averages);
2891 Thyra::Ordinal rows = v->range()->dim();
2892 for (std::size_t i = 0; i < averages.size(); i++) averages[i] = averages[i] / rows;
2895 double average(
const MultiVector &v) {
2896 Thyra::Ordinal rows = v->range()->dim();
2897 Thyra::Ordinal cols = v->domain()->dim();
2899 std::vector<double> averages;
2900 columnAverages(v, averages);
2903 for (std::size_t i = 0; i < averages.size(); i++) sum += averages[i] * rows;
2905 return sum / (rows * cols);
2908 bool isPhysicallyBlockedLinearOp(
const LinearOp &op) {
2910 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> pblo =
2911 rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(op);
2912 if (!pblo.is_null())
return true;
2916 Thyra::EOpTransp transp = Thyra::NOTRANS;
2917 RCP<const Thyra::LinearOpBase<ST>> wrapped_op;
2918 Thyra::unwrap(op, &scalar, &transp, &wrapped_op);
2919 pblo = rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(wrapped_op);
2920 if (!pblo.is_null())
return true;
2925 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> getPhysicallyBlockedLinearOp(
2926 const LinearOp &op, ST *scalar,
bool *transp) {
2928 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> pblo =
2929 rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(op);
2930 if (!pblo.is_null()) {
2937 RCP<const Thyra::LinearOpBase<ST>> wrapped_op;
2938 Thyra::EOpTransp eTransp = Thyra::NOTRANS;
2939 Thyra::unwrap(op, scalar, &eTransp, &wrapped_op);
2940 pblo = rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(wrapped_op,
true);
2941 if (!pblo.is_null()) {
2943 if (eTransp == Thyra::NOTRANS) *transp =
false;
2947 return Teuchos::null;
2950 std::string formatBlockName(
const std::string &prefix,
int i,
int j,
int nrow) {
2951 unsigned digits = 0;
2952 auto blockId = nrow - 1;
2958 std::ostringstream ss;
2959 ss << prefix <<
"_";
2960 ss << std::setfill(
'0') << std::setw(digits) << i;
2962 ss << std::setfill(
'0') << std::setw(digits) << j;
Implements the Epetra_Operator interface with a Thyra LinearOperator. This enables the use of absrtac...