10 #include "Teko_Config.h"
14 #include "Thyra_MultiVectorStdOps.hpp"
15 #include "Thyra_ZeroLinearOpBase.hpp"
16 #include "Thyra_DefaultDiagonalLinearOp.hpp"
17 #include "Thyra_DefaultAddedLinearOp.hpp"
18 #include "Thyra_DefaultScaledAdjointLinearOp.hpp"
19 #include "Thyra_DefaultMultipliedLinearOp.hpp"
20 #include "Thyra_DefaultZeroLinearOp.hpp"
21 #include "Thyra_DefaultProductMultiVector.hpp"
22 #include "Thyra_DefaultProductVectorSpace.hpp"
23 #include "Thyra_MultiVectorStdOps.hpp"
24 #include "Thyra_VectorStdOps.hpp"
25 #include "Thyra_SpmdVectorBase.hpp"
28 #ifdef TEKO_HAVE_EPETRA
29 #include "Thyra_EpetraExtDiagScaledMatProdTransformer.hpp"
30 #include "Thyra_EpetraExtDiagScalingTransformer.hpp"
31 #include "Thyra_EpetraExtAddTransformer.hpp"
32 #include "Thyra_get_Epetra_Operator.hpp"
33 #include "Thyra_EpetraThyraWrappers.hpp"
34 #include "Thyra_EpetraOperatorWrapper.hpp"
35 #include "Thyra_EpetraLinearOp.hpp"
39 #include "Teuchos_Array.hpp"
42 #ifdef TEKO_HAVE_EPETRA
43 #include "Epetra_Operator.h"
44 #include "Epetra_CrsGraph.h"
45 #include "Epetra_CrsMatrix.h"
46 #include "Epetra_Vector.h"
47 #include "Epetra_Map.h"
49 #include "EpetraExt_Transpose_RowMatrix.h"
50 #include "EpetraExt_MatrixMatrix.h"
51 #include <EpetraExt_BlockMapOut.h>
52 #include <EpetraExt_RowMatrixOut.h>
54 #include "Teko_EpetraHelpers.hpp"
55 #include "Teko_EpetraOperatorWrapper.hpp"
59 #include "AnasaziBasicEigenproblem.hpp"
60 #include "AnasaziThyraAdapter.hpp"
61 #include "AnasaziBlockKrylovSchurSolMgr.hpp"
62 #include "AnasaziBlockKrylovSchur.hpp"
63 #include "AnasaziStatusTestMaxIters.hpp"
66 #ifdef Teko_ENABLE_Isorropia
67 #include "Isorropia_EpetraProber.hpp"
71 #include "Teko_TpetraHelpers.hpp"
72 #include "Teko_TpetraOperatorWrapper.hpp"
75 #include "Thyra_TpetraLinearOp.hpp"
76 #include "Tpetra_CrsMatrix.hpp"
77 #include "Tpetra_Vector.hpp"
78 #include "Thyra_TpetraThyraWrappers.hpp"
79 #include "TpetraExt_MatrixMatrix.hpp"
80 #include "Tpetra_RowMatrixTransposer.hpp"
81 #include "MatrixMarket_Tpetra.hpp"
89 using Teuchos::rcp_dynamic_cast;
90 #ifdef Teko_ENABLE_Isorropia
91 using Isorropia::Epetra::Prober;
94 const Teuchos::RCP<Teuchos::FancyOStream> getOutputStream() {
95 Teuchos::RCP<Teuchos::FancyOStream> os = Teuchos::VerboseObjectBase::getDefaultOStream();
103 inline double dist(
int dim,
double *coords,
int row,
int col) {
105 for (
int i = 0; i < dim; i++)
106 value += std::pow(coords[dim * row + i] - coords[dim * col + i], 2.0);
109 return std::sqrt(value);
113 inline double dist(
double *x,
double *y,
double *z,
int stride,
int row,
int col) {
115 if (x != 0) value += std::pow(x[stride * row] - x[stride * col], 2.0);
116 if (y != 0) value += std::pow(y[stride * row] - y[stride * col], 2.0);
117 if (z != 0) value += std::pow(z[stride * row] - z[stride * col], 2.0);
120 return std::sqrt(value);
141 #ifdef TEKO_HAVE_EPETRA
142 RCP<Epetra_CrsMatrix> buildGraphLaplacian(
int dim,
double *coords,
143 const Epetra_CrsMatrix &stencil) {
146 RCP<Epetra_CrsMatrix> gl = rcp(
147 new Epetra_CrsMatrix(Copy, stencil.RowMap(), stencil.ColMap(), stencil.MaxNumEntries() + 1),
151 std::vector<double> rowData(stencil.GlobalMaxNumEntries() + 1);
152 std::vector<int> rowInd(stencil.GlobalMaxNumEntries() + 1);
155 for (
int j = 0; j < gl->NumMyRows(); j++) {
156 int row = gl->GRID(j);
157 double diagValue = 0.0;
162 stencil.ExtractGlobalRowCopy(row, stencil.MaxNumEntries(), rowSz, &rowData[0], &rowInd[0]);
165 for (
int i = 0; i < rowSz; i++) {
169 double value = rowData[i];
170 if (value == 0)
continue;
174 double d = dist(dim, coords, row, col);
175 rowData[i] = -1.0 / d;
176 diagValue += rowData[i];
183 rowData[rowSz] = -diagValue;
187 rowData[diagInd] = -diagValue;
188 rowInd[diagInd] = row;
192 TEUCHOS_TEST_FOR_EXCEPT(gl->InsertGlobalValues(row, rowSz, &rowData[0], &rowInd[0]));
201 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> buildGraphLaplacian(
202 int dim, ST *coords,
const Tpetra::CrsMatrix<ST, LO, GO, NT> &stencil) {
205 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> gl = rcp(
new Tpetra::CrsMatrix<ST, LO, GO, NT>(
206 stencil.getRowMap(), stencil.getColMap(), stencil.getGlobalMaxNumRowEntries() + 1));
209 auto rowInd =
typename Tpetra::CrsMatrix<ST, LO, GO, NT>::nonconst_global_inds_host_view_type(
210 Kokkos::ViewAllocateWithoutInitializing(
"rowIndices"),
211 stencil.getGlobalMaxNumRowEntries() + 1);
212 auto rowData =
typename Tpetra::CrsMatrix<ST, LO, GO, NT>::nonconst_values_host_view_type(
213 Kokkos::ViewAllocateWithoutInitializing(
"rowIndices"),
214 stencil.getGlobalMaxNumRowEntries() + 1);
217 for (LO j = 0; j < (LO)gl->getLocalNumRows(); j++) {
218 GO row = gl->getRowMap()->getGlobalElement(j);
224 stencil.getGlobalRowCopy(row, rowInd, rowData, rowSz);
227 for (
size_t i = 0; i < rowSz; i++) {
231 ST value = rowData[i];
232 if (value == 0)
continue;
236 ST d = dist(dim, coords, row, col);
237 rowData[i] = -1.0 / d;
238 diagValue += rowData(i);
245 rowData(rowSz) = -diagValue;
249 rowData(diagInd) = -diagValue;
250 rowInd(diagInd) = row;
254 gl->replaceGlobalValues(row, rowInd, rowData);
284 #ifdef TEKO_HAVE_EPETRA
285 RCP<Epetra_CrsMatrix> buildGraphLaplacian(
double *x,
double *y,
double *z,
int stride,
286 const Epetra_CrsMatrix &stencil) {
289 RCP<Epetra_CrsMatrix> gl = rcp(
290 new Epetra_CrsMatrix(Copy, stencil.RowMap(), stencil.ColMap(), stencil.MaxNumEntries() + 1),
294 std::vector<double> rowData(stencil.GlobalMaxNumEntries() + 1);
295 std::vector<int> rowInd(stencil.GlobalMaxNumEntries() + 1);
298 for (
int j = 0; j < gl->NumMyRows(); j++) {
299 int row = gl->GRID(j);
300 double diagValue = 0.0;
305 stencil.ExtractGlobalRowCopy(row, stencil.MaxNumEntries(), rowSz, &rowData[0], &rowInd[0]);
308 for (
int i = 0; i < rowSz; i++) {
312 double value = rowData[i];
313 if (value == 0)
continue;
317 double d = dist(x, y, z, stride, row, col);
318 rowData[i] = -1.0 / d;
319 diagValue += rowData[i];
326 rowData[rowSz] = -diagValue;
330 rowData[diagInd] = -diagValue;
331 rowInd[diagInd] = row;
335 TEUCHOS_TEST_FOR_EXCEPT(gl->InsertGlobalValues(row, rowSz, &rowData[0], &rowInd[0]));
344 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> buildGraphLaplacian(
345 ST *x, ST *y, ST *z, GO stride,
const Tpetra::CrsMatrix<ST, LO, GO, NT> &stencil) {
348 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> gl =
349 rcp(
new Tpetra::CrsMatrix<ST, LO, GO, NT>(stencil.getRowMap(), stencil.getColMap(),
350 stencil.getGlobalMaxNumRowEntries() + 1),
354 auto rowInd =
typename Tpetra::CrsMatrix<ST, LO, GO, NT>::nonconst_global_inds_host_view_type(
355 Kokkos::ViewAllocateWithoutInitializing(
"rowIndices"),
356 stencil.getGlobalMaxNumRowEntries() + 1);
357 auto rowData =
typename Tpetra::CrsMatrix<ST, LO, GO, NT>::nonconst_values_host_view_type(
358 Kokkos::ViewAllocateWithoutInitializing(
"rowIndices"),
359 stencil.getGlobalMaxNumRowEntries() + 1);
362 for (LO j = 0; j < (LO)gl->getLocalNumRows(); j++) {
363 GO row = gl->getRowMap()->getGlobalElement(j);
369 stencil.getGlobalRowCopy(row, rowInd, rowData, rowSz);
372 for (
size_t i = 0; i < rowSz; i++) {
376 ST value = rowData[i];
377 if (value == 0)
continue;
381 ST d = dist(x, y, z, stride, row, col);
382 rowData[i] = -1.0 / d;
383 diagValue += rowData(i);
390 rowData(rowSz) = -diagValue;
394 rowData(diagInd) = -diagValue;
395 rowInd(diagInd) = row;
399 gl->replaceGlobalValues(row, rowInd, rowData);
422 void applyOp(
const LinearOp &A,
const MultiVector &x, MultiVector &y,
double alpha,
double beta) {
423 Thyra::apply(*A, Thyra::NOTRANS, *x, y.ptr(), alpha, beta);
441 void applyTransposeOp(
const LinearOp &A,
const MultiVector &x, MultiVector &y,
double alpha,
443 Thyra::apply(*A, Thyra::TRANS, *x, y.ptr(), alpha, beta);
448 void update(
double alpha,
const MultiVector &x,
double beta, MultiVector &y) {
449 Teuchos::Array<double> scale;
450 Teuchos::Array<Teuchos::Ptr<const Thyra::MultiVectorBase<double>>> vec;
453 scale.push_back(alpha);
454 vec.push_back(x.ptr());
457 Thyra::linear_combination<double>(scale, vec, beta, y.ptr());
461 BlockedLinearOp getUpperTriBlocks(
const BlockedLinearOp &blo,
bool callEndBlockFill) {
462 int rows = blockRowCount(blo);
464 TEUCHOS_ASSERT(rows == blockColCount(blo));
466 RCP<const Thyra::ProductVectorSpaceBase<double>> range = blo->productRange();
467 RCP<const Thyra::ProductVectorSpaceBase<double>> domain = blo->productDomain();
470 BlockedLinearOp upper = createBlockedOp();
473 upper->beginBlockFill(rows, rows);
475 for (
int i = 0; i < rows; i++) {
479 RCP<const Thyra::LinearOpBase<double>> zed =
480 Thyra::zero<double>(range->getBlock(i), domain->getBlock(i));
481 upper->setBlock(i, i, zed);
483 for (
int j = i + 1; j < rows; j++) {
485 LinearOp uij = blo->getBlock(i, j);
488 if (uij != Teuchos::null) upper->setBlock(i, j, uij);
491 if (callEndBlockFill) upper->endBlockFill();
497 BlockedLinearOp getLowerTriBlocks(
const BlockedLinearOp &blo,
bool callEndBlockFill) {
498 int rows = blockRowCount(blo);
500 TEUCHOS_ASSERT(rows == blockColCount(blo));
502 RCP<const Thyra::ProductVectorSpaceBase<double>> range = blo->productRange();
503 RCP<const Thyra::ProductVectorSpaceBase<double>> domain = blo->productDomain();
506 BlockedLinearOp lower = createBlockedOp();
509 lower->beginBlockFill(rows, rows);
511 for (
int i = 0; i < rows; i++) {
515 RCP<const Thyra::LinearOpBase<double>> zed =
516 Thyra::zero<double>(range->getBlock(i), domain->getBlock(i));
517 lower->setBlock(i, i, zed);
519 for (
int j = 0; j < i; j++) {
521 LinearOp uij = blo->getBlock(i, j);
524 if (uij != Teuchos::null) lower->setBlock(i, j, uij);
527 if (callEndBlockFill) lower->endBlockFill();
551 BlockedLinearOp zeroBlockedOp(
const BlockedLinearOp &blo) {
552 int rows = blockRowCount(blo);
554 TEUCHOS_ASSERT(rows == blockColCount(blo));
556 RCP<const Thyra::ProductVectorSpaceBase<double>> range = blo->productRange();
557 RCP<const Thyra::ProductVectorSpaceBase<double>> domain = blo->productDomain();
560 BlockedLinearOp zeroOp = createBlockedOp();
563 zeroOp->beginBlockFill(rows, rows);
565 for (
int i = 0; i < rows; i++) {
569 RCP<const Thyra::LinearOpBase<double>> zed =
570 Thyra::zero<double>(range->getBlock(i), domain->getBlock(i));
571 zeroOp->setBlock(i, i, zed);
578 bool isZeroOp(
const LinearOp op) {
580 if (op == Teuchos::null)
return true;
583 LinearOp test = rcp_dynamic_cast<
const Thyra::ZeroLinearOpBase<double>>(op);
586 if (test != Teuchos::null)
return true;
590 Thyra::EOpTransp transp = Thyra::NOTRANS;
591 RCP<const Thyra::LinearOpBase<ST>> wrapped_op;
592 Thyra::unwrap(op, &scalar, &transp, &wrapped_op);
593 test = rcp_dynamic_cast<
const Thyra::ZeroLinearOpBase<double>>(wrapped_op);
594 return test != Teuchos::null;
597 std::pair<ModifiableLinearOp, bool> getAbsRowSumMatrixEpetra(
const LinearOp &op) {
598 #ifndef TEKO_HAVE_EPETRA
599 return std::make_pair(ModifiableLinearOp{},
false);
601 RCP<const Epetra_CrsMatrix> eCrsOp;
603 const auto eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op);
606 return std::make_pair(ModifiableLinearOp{},
false);
609 eCrsOp = rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
612 const auto ptrDiag = rcp(
new Epetra_Vector(eCrsOp->RowMap()));
613 Epetra_Vector &diag = *ptrDiag;
617 for (
int i = 0; i < eCrsOp->NumMyRows(); i++) {
620 eCrsOp->ExtractMyRowView(i, numEntries, values);
623 for (
int j = 0; j < numEntries; j++) diag[i] += std::abs(values[j]);
627 return std::make_pair(Teko::Epetra::thyraDiagOp(ptrDiag, eCrsOp->RowMap(),
628 "absRowSum( " + op->getObjectLabel() +
" )"),
633 std::pair<ModifiableLinearOp, bool> getAbsRowSumMatrixTpetra(
const LinearOp &op) {
634 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp;
636 const auto tOp = rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op);
638 tCrsOp = rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
642 const auto ptrDiag = Tpetra::createVector<ST, LO, GO, NT>(tCrsOp->getRowMap());
643 auto &diag = *ptrDiag;
647 for (LO i = 0; i < (LO)tCrsOp->getLocalNumRows(); i++) {
648 auto numEntries = tCrsOp->getNumEntriesInLocalRow(i);
649 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::local_inds_host_view_type indices;
650 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::values_host_view_type values;
651 tCrsOp->getLocalRowView(i, indices, values);
654 for (
size_t j = 0; j < numEntries; j++) diag.sumIntoLocalValue(i, std::abs(values(j)));
658 return std::make_pair(
659 Teko::TpetraHelpers::thyraDiagOp(ptrDiag, *tCrsOp->getRowMap(),
660 "absRowSum( " + op->getObjectLabel() +
" ))"),
672 ModifiableLinearOp getAbsRowSumMatrix(
const LinearOp &op) {
674 auto eResult = getAbsRowSumMatrixEpetra(op);
675 if (eResult.second) {
676 return eResult.first;
679 auto tResult = getAbsRowSumMatrixTpetra(op);
680 if (tResult.second) {
681 return tResult.first;
683 throw std::logic_error(
"Neither Epetra nor Tpetra");
685 }
catch (std::exception &e) {
686 auto out = Teuchos::VerboseObjectBase::getDefaultOStream();
688 *out <<
"Teko: getAbsRowSumMatrix requires an Epetra_CrsMatrix or a "
689 "Tpetra::CrsMatrix\n";
690 *out <<
" Could not extract an Epetra_Operator or a Tpetra_Operator "
692 << op->description() << std::endl;
694 *out <<
" Could not cast an Epetra_Operator to a Epetra_CrsMatrix or "
695 "a Tpetra_Operator to a Tpetra::CrsMatrix\n";
697 *out <<
"*** THROWN EXCEPTION ***\n";
698 *out << e.what() << std::endl;
699 *out <<
"************************\n";
713 ModifiableLinearOp getAbsRowSumInvMatrix(
const LinearOp &op) {
716 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_op =
717 rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(op);
718 if (blocked_op != Teuchos::null) {
719 int numRows = blocked_op->productRange()->numBlocks();
720 TEUCHOS_ASSERT(blocked_op->productDomain()->numBlocks() == numRows);
721 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_diag =
722 Thyra::defaultBlockedLinearOp<double>();
723 blocked_diag->beginBlockFill(numRows, numRows);
724 for (
int r = 0; r < numRows; ++r) {
725 for (
int c = 0; c < numRows; ++c) {
727 blocked_diag->setNonconstBlock(r, c, getAbsRowSumInvMatrix(blocked_op->getBlock(r, c)));
729 blocked_diag->setBlock(r, c,
730 Thyra::zero<double>(blocked_op->getBlock(r, c)->range(),
731 blocked_op->getBlock(r, c)->domain()));
734 blocked_diag->endBlockFill();
738 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
741 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp =
742 Teko::TpetraHelpers::getTpetraCrsMatrix(op, &scalar, &transp);
745 const RCP<Tpetra::Vector<ST, LO, GO, NT>> ptrDiag =
746 Tpetra::createVector<ST, LO, GO, NT>(tCrsOp->getRowMap());
747 Tpetra::Vector<ST, LO, GO, NT> &diag = *ptrDiag;
751 for (LO i = 0; i < (LO)tCrsOp->getLocalNumRows(); i++) {
752 LO numEntries = tCrsOp->getNumEntriesInLocalRow(i);
753 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::local_inds_host_view_type indices;
754 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::values_host_view_type values;
755 tCrsOp->getLocalRowView(i, indices, values);
758 for (LO j = 0; j < numEntries; j++) diag.sumIntoLocalValue(i, std::abs(values(j)));
761 diag.reciprocal(diag);
764 return Teko::TpetraHelpers::thyraDiagOp(ptrDiag, *tCrsOp->getRowMap(),
765 "absRowSum( " + op->getObjectLabel() +
" ))");
768 #ifdef TEKO_HAVE_EPETRA
769 RCP<const Thyra::EpetraLinearOp> eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op,
true);
770 RCP<const Epetra_CrsMatrix> eCrsOp =
771 rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
774 const RCP<Epetra_Vector> ptrDiag = rcp(
new Epetra_Vector(eCrsOp->RowMap()));
775 Epetra_Vector &diag = *ptrDiag;
779 for (
int i = 0; i < eCrsOp->NumMyRows(); i++) {
782 eCrsOp->ExtractMyRowView(i, numEntries, values);
785 for (
int j = 0; j < numEntries; j++) diag[i] += std::abs(values[j]);
787 diag.Reciprocal(diag);
790 return Teko::Epetra::thyraDiagOp(ptrDiag, eCrsOp->RowMap(),
791 "absRowSum( " + op->getObjectLabel() +
" )");
793 throw std::logic_error(
794 "getAbsRowSumInvMatrix is trying to use Epetra "
795 "code, but TEKO_HAVE_EPETRA is disabled!");
807 ModifiableLinearOp getLumpedMatrix(
const LinearOp &op) {
808 RCP<Thyra::VectorBase<ST>> ones = Thyra::createMember(op->domain());
809 RCP<Thyra::VectorBase<ST>> diag = Thyra::createMember(op->range());
812 Thyra::assign(ones.ptr(), 1.0);
816 Thyra::apply(*op, Thyra::NOTRANS, *ones, diag.ptr());
818 return rcp(
new Thyra::DefaultDiagonalLinearOp<ST>(diag));
829 ModifiableLinearOp getInvLumpedMatrix(
const LinearOp &op) {
830 RCP<Thyra::VectorBase<ST>> ones = Thyra::createMember(op->domain());
831 RCP<Thyra::VectorBase<ST>> diag = Thyra::createMember(op->range());
834 Thyra::assign(ones.ptr(), 1.0);
837 Thyra::apply(*op, Thyra::NOTRANS, *ones, diag.ptr());
838 Thyra::reciprocal(*diag, diag.ptr());
840 return rcp(
new Thyra::DefaultDiagonalLinearOp<ST>(diag));
843 const std::pair<ModifiableLinearOp, bool> getDiagonalOpEpetra(
const LinearOp &op) {
844 #ifndef TEKO_HAVE_EPETRA
845 return std::make_pair(ModifiableLinearOp{},
false);
847 RCP<const Epetra_CrsMatrix> eCrsOp;
849 const auto eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op);
851 return std::make_pair(ModifiableLinearOp{},
false);
854 eCrsOp = rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
857 const auto diag = rcp(
new Epetra_Vector(eCrsOp->RowMap()));
858 TEUCHOS_TEST_FOR_EXCEPT(eCrsOp->ExtractDiagonalCopy(*diag));
861 return std::make_pair(Teko::Epetra::thyraDiagOp(diag, eCrsOp->RowMap(),
862 "inv(diag( " + op->getObjectLabel() +
" ))"),
867 const std::pair<ModifiableLinearOp, bool> getDiagonalOpTpetra(
const LinearOp &op) {
868 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp;
870 const auto tOp = rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op);
872 return std::make_pair(ModifiableLinearOp{},
false);
875 tCrsOp = rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
879 const auto diag = Tpetra::createVector<ST, LO, GO, NT>(tCrsOp->getRowMap());
880 tCrsOp->getLocalDiagCopy(*diag);
883 return std::make_pair(
884 Teko::TpetraHelpers::thyraDiagOp(diag, *tCrsOp->getRowMap(),
885 "inv(diag( " + op->getObjectLabel() +
" ))"),
900 const ModifiableLinearOp getDiagonalOp(
const LinearOp &op) {
903 const auto eDiagOp = getDiagonalOpEpetra(op);
905 if (eDiagOp.second) {
906 return eDiagOp.first;
909 const auto tDiagOp = getDiagonalOpTpetra(op);
910 if (tDiagOp.second) {
911 return tDiagOp.first;
913 throw std::logic_error(
"Neither Epetra nor Tpetra");
914 }
catch (std::exception &e) {
915 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
917 *out <<
"Teko: getDiagonalOp requires an Epetra_CrsMatrix or a Tpetra::CrsMatrix\n";
918 *out <<
" Could not extract an Epetra_Operator or a Tpetra_Operator from a \""
919 << op->description() << std::endl;
921 *out <<
" Could not cast an Epetra_Operator to a Epetra_CrsMatrix or a Tpetra_Operator to a "
922 "Tpetra::CrsMatrix\n";
924 *out <<
"*** THROWN EXCEPTION ***\n";
925 *out << e.what() << std::endl;
926 *out <<
"************************\n";
932 const MultiVector getDiagonal(
const LinearOp &op) {
935 auto diagOp = getDiagonalOpEpetra(op);
937 if (!diagOp.second) {
938 diagOp = getDiagonalOpTpetra(op);
940 if (!diagOp.second) {
941 throw std::logic_error(
"Neither Epetra nor Tpetra");
945 Teuchos::RCP<const Thyra::MultiVectorBase<double>> v =
946 Teuchos::rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<double>>(diagOp.first)
948 return Teuchos::rcp_const_cast<Thyra::MultiVectorBase<double>>(v);
949 }
catch (std::exception &e) {
950 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
952 *out <<
"Teko: getDiagonal requires an Epetra_CrsMatrix or a Tpetra::CrsMatrix\n";
953 *out <<
" Could not extract an Epetra_Operator or a Tpetra_Operator from a \""
954 << op->description() << std::endl;
956 *out <<
" Could not cast an Epetra_Operator to a Epetra_CrsMatrix or a Tpetra_Operator to a "
957 "Tpetra::CrsMatrix\n";
959 *out <<
"*** THROWN EXCEPTION ***\n";
960 *out << e.what() << std::endl;
961 *out <<
"************************\n";
967 const MultiVector getDiagonal(
const Teko::LinearOp &A,
const DiagonalType &dt) {
968 LinearOp diagOp = Teko::getDiagonalOp(A, dt);
970 Teuchos::RCP<const Thyra::MultiVectorBase<double>> v =
971 Teuchos::rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<double>>(diagOp)->getDiag();
972 return Teuchos::rcp_const_cast<Thyra::MultiVectorBase<double>>(v);
986 const ModifiableLinearOp getInvDiagonalOp(
const LinearOp &op) {
988 auto diagonal_op = rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<double>>(op);
989 if (diagonal_op != Teuchos::null) {
990 auto diag = diagonal_op->getDiag();
991 auto inv_diag = diag->clone_v();
992 Thyra::reciprocal(*diag, inv_diag.ptr());
993 return rcp(
new Thyra::DefaultDiagonalLinearOp<double>(inv_diag));
997 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_op =
998 rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(op);
999 if (blocked_op != Teuchos::null) {
1000 int numRows = blocked_op->productRange()->numBlocks();
1001 TEUCHOS_ASSERT(blocked_op->productDomain()->numBlocks() == numRows);
1002 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_diag =
1003 Thyra::defaultBlockedLinearOp<double>();
1004 blocked_diag->beginBlockFill(numRows, numRows);
1005 for (
int r = 0; r < numRows; ++r) {
1006 for (
int c = 0; c < numRows; ++c) {
1008 blocked_diag->setNonconstBlock(r, c, getInvDiagonalOp(blocked_op->getBlock(r, c)));
1010 blocked_diag->setBlock(r, c,
1011 Thyra::zero<double>(blocked_op->getBlock(r, c)->range(),
1012 blocked_op->getBlock(r, c)->domain()));
1015 blocked_diag->endBlockFill();
1016 return blocked_diag;
1019 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
1021 bool transp =
false;
1022 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp =
1023 Teko::TpetraHelpers::getTpetraCrsMatrix(op, &scalar, &transp);
1026 const RCP<Tpetra::Vector<ST, LO, GO, NT>> diag =
1027 Tpetra::createVector<ST, LO, GO, NT>(tCrsOp->getRowMap());
1028 diag->scale(scalar);
1029 tCrsOp->getLocalDiagCopy(*diag);
1030 diag->reciprocal(*diag);
1033 return Teko::TpetraHelpers::thyraDiagOp(diag, *tCrsOp->getRowMap(),
1034 "inv(diag( " + op->getObjectLabel() +
" ))");
1037 #ifdef TEKO_HAVE_EPETRA
1038 RCP<const Thyra::EpetraLinearOp> eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op,
true);
1039 RCP<const Epetra_CrsMatrix> eCrsOp =
1040 rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
1043 const RCP<Epetra_Vector> diag = rcp(
new Epetra_Vector(eCrsOp->RowMap()));
1044 TEUCHOS_TEST_FOR_EXCEPT(eCrsOp->ExtractDiagonalCopy(*diag));
1045 diag->Reciprocal(*diag);
1048 return Teko::Epetra::thyraDiagOp(diag, eCrsOp->RowMap(),
1049 "inv(diag( " + op->getObjectLabel() +
" ))");
1051 throw std::logic_error(
1052 "getInvDiagonalOp is trying to use Epetra "
1053 "code, but TEKO_HAVE_EPETRA is disabled!");
1070 const LinearOp explicitMultiply(
const LinearOp &opl,
const LinearOp &opm,
const LinearOp &opr) {
1075 bool isBlockedL = isPhysicallyBlockedLinearOp(opl);
1076 bool isBlockedM = isPhysicallyBlockedLinearOp(opm);
1077 bool isBlockedR = isPhysicallyBlockedLinearOp(opr);
1080 if ((isBlockedL && isBlockedM && isBlockedR)) {
1081 double scalarl = 0.0;
1082 bool transpl =
false;
1083 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1084 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1085 double scalarm = 0.0;
1086 bool transpm =
false;
1087 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opm =
1088 getPhysicallyBlockedLinearOp(opm, &scalarm, &transpm);
1089 double scalarr = 0.0;
1090 bool transpr =
false;
1091 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1092 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1093 double scalar = scalarl * scalarm * scalarr;
1095 int numRows = blocked_opl->productRange()->numBlocks();
1096 int numCols = blocked_opr->productDomain()->numBlocks();
1097 int numMiddle = blocked_opm->productRange()->numBlocks();
1101 TEUCHOS_ASSERT(blocked_opm->productDomain()->numBlocks() == numMiddle);
1102 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1103 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1105 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1106 Thyra::defaultBlockedLinearOp<double>();
1107 blocked_product->beginBlockFill(numRows, numCols);
1108 for (
int r = 0; r < numRows; ++r) {
1109 for (
int c = 0; c < numCols; ++c) {
1110 LinearOp product_rc = explicitMultiply(
1111 blocked_opl->getBlock(r, 0), blocked_opm->getBlock(0, 0), blocked_opr->getBlock(0, c));
1112 for (
int m = 1; m < numMiddle; ++m) {
1113 LinearOp product_m =
1114 explicitMultiply(blocked_opl->getBlock(r, m), blocked_opm->getBlock(m, m),
1115 blocked_opr->getBlock(m, c));
1116 product_rc = explicitAdd(product_rc, product_m);
1118 blocked_product->setBlock(r, c, product_rc);
1121 blocked_product->endBlockFill();
1122 return Thyra::scale<double>(scalar, blocked_product.getConst());
1126 if (isBlockedL && !isBlockedM && isBlockedR) {
1127 double scalarl = 0.0;
1128 bool transpl =
false;
1129 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1130 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1131 double scalarr = 0.0;
1132 bool transpr =
false;
1133 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1134 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1135 double scalar = scalarl * scalarr;
1137 int numRows = blocked_opl->productRange()->numBlocks();
1138 int numCols = blocked_opr->productDomain()->numBlocks();
1142 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1143 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1145 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1146 Thyra::defaultBlockedLinearOp<double>();
1147 blocked_product->beginBlockFill(numRows, numCols);
1148 for (
int r = 0; r < numRows; ++r) {
1149 for (
int c = 0; c < numCols; ++c) {
1150 LinearOp product_rc =
1151 explicitMultiply(blocked_opl->getBlock(r, 0), opm, blocked_opr->getBlock(0, c));
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 scalarr = 0.0;
1162 bool transpr =
false;
1163 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1164 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1165 double scalar = scalarr;
1168 int numCols = blocked_opr->productDomain()->numBlocks();
1172 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1174 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1175 Thyra::defaultBlockedLinearOp<double>();
1176 blocked_product->beginBlockFill(numRows, numCols);
1177 for (
int c = 0; c < numCols; ++c) {
1178 LinearOp product_c = explicitMultiply(opl, opm, blocked_opr->getBlock(0, c));
1179 blocked_product->setBlock(0, c, product_c);
1181 blocked_product->endBlockFill();
1182 return Thyra::scale<double>(scalar, blocked_product.getConst());
1187 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1188 bool isTpetram = Teko::TpetraHelpers::isTpetraLinearOp(opm);
1189 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1191 if (isTpetral && isTpetram &&
1196 bool transpl =
false;
1197 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1198 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1200 bool transpm =
false;
1201 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpm =
1202 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarm, &transpm);
1204 bool transpr =
false;
1205 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1206 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1209 RCP<Thyra::LinearOpBase<ST>> explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1210 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
1211 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
1214 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOplm =
1215 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1216 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1217 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1218 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOpl, transpl, *tCrsOpm, transpm, *tCrsOplm);
1219 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOplm,
false, *tCrsOpr, transpr,
1221 explicitCrsOp->resumeFill();
1222 explicitCrsOp->scale(scalarl * scalarm * scalarr);
1223 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1224 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1225 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1229 }
else if (isTpetral && !isTpetram && isTpetrar) {
1233 bool transpl =
false;
1234 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1235 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1237 bool transpr =
false;
1238 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1239 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1241 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr;
1244 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpm =
1245 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opm);
1246 if (dOpm != Teuchos::null) {
1247 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1248 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpm->getDiag(),
true);
1249 diagPtr = rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
1253 else if (rcp_dynamic_cast<
const Thyra::ZeroLinearOpBase<ST>>(opm) != Teuchos::null) {
1254 diagPtr = rcp(
new Tpetra::Vector<ST, LO, GO, NT>(tCrsOpl->getDomainMap()));
1256 TEUCHOS_ASSERT(
false);
1258 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOplm =
1259 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1260 tCrsOpl, Tpetra::Import<LO, GO, NT>(tCrsOpl->getRowMap(), tCrsOpl->getRowMap()));
1263 tCrsOplm->rightScale(*diagPtr);
1266 RCP<Thyra::LinearOpBase<ST>> explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1267 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
1268 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
1271 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1272 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1273 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOplm,
false, *tCrsOpr, transpr,
1275 explicitCrsOp->resumeFill();
1276 explicitCrsOp->scale(scalarl * scalarr);
1277 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1278 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1279 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1284 #ifdef TEKO_HAVE_EPETRA
1286 const LinearOp implicitOp = Thyra::multiply(opl, opm, opr);
1289 const RCP<Thyra::LinearOpTransformerBase<double>> prodTrans =
1290 Thyra::epetraExtDiagScaledMatProdTransformer();
1293 const RCP<Thyra::LinearOpBase<double>> explicitOp = prodTrans->createOutputOp();
1294 prodTrans->transform(*implicitOp, explicitOp.ptr());
1295 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" * " +
1296 opm->getObjectLabel() +
" * " + opr->getObjectLabel() +
" )");
1300 throw std::logic_error(
1301 "explicitMultiply is trying to use Epetra "
1302 "code, but TEKO_HAVE_EPETRA is disabled!");
1321 const ModifiableLinearOp explicitMultiply(
const LinearOp &opl,
const LinearOp &opm,
1322 const LinearOp &opr,
const ModifiableLinearOp &destOp) {
1323 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1324 bool isTpetram = Teko::TpetraHelpers::isTpetraLinearOp(opm);
1325 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1327 if (isTpetral && isTpetram &&
1332 bool transpl =
false;
1333 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1334 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1336 bool transpm =
false;
1337 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpm =
1338 Teko::TpetraHelpers::getTpetraCrsMatrix(opm, &scalarm, &transpm);
1340 bool transpr =
false;
1341 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1342 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1345 auto tExplicitOp = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(destOp);
1346 if (tExplicitOp.is_null()) tExplicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1349 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOplm =
1350 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1351 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1352 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1353 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOpl, transpl, *tCrsOpm, transpm, *tCrsOplm);
1354 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOplm,
false, *tCrsOpr, transpr,
1356 explicitCrsOp->resumeFill();
1357 explicitCrsOp->scale(scalarl * scalarm * scalarr);
1358 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1359 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1360 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1364 }
else if (isTpetral && !isTpetram && isTpetrar) {
1368 bool transpl =
false;
1369 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1370 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1372 bool transpr =
false;
1373 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1374 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1377 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpm =
1378 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opm,
true);
1379 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1380 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpm->getDiag(),
true);
1381 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr =
1382 rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
true);
1383 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOplm =
1384 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1385 tCrsOpl, Tpetra::Import<LO, GO, NT>(tCrsOpl->getRowMap(), tCrsOpl->getRowMap()));
1388 tCrsOplm->rightScale(*diagPtr);
1391 RCP<Thyra::LinearOpBase<ST>> explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1392 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
1393 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
1396 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1397 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1398 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOplm,
false, *tCrsOpr, transpr,
1400 explicitCrsOp->resumeFill();
1401 explicitCrsOp->scale(scalarl * scalarr);
1402 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1403 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1404 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1409 #ifdef TEKO_HAVE_EPETRA
1411 const LinearOp implicitOp = Thyra::multiply(opl, opm, opr);
1414 const RCP<Thyra::LinearOpTransformerBase<double>> prodTrans =
1415 Thyra::epetraExtDiagScaledMatProdTransformer();
1418 ModifiableLinearOp explicitOp;
1421 if (destOp == Teuchos::null)
1422 explicitOp = prodTrans->createOutputOp();
1424 explicitOp = destOp;
1427 prodTrans->transform(*implicitOp, explicitOp.ptr());
1430 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" * " +
1431 opm->getObjectLabel() +
" * " + opr->getObjectLabel() +
" )");
1435 throw std::logic_error(
1436 "explicitMultiply is trying to use Epetra "
1437 "code, but TEKO_HAVE_EPETRA is disabled!");
1452 const LinearOp explicitMultiply(
const LinearOp &opl,
const LinearOp &opr) {
1457 bool isBlockedL = isPhysicallyBlockedLinearOp(opl);
1458 bool isBlockedR = isPhysicallyBlockedLinearOp(opr);
1461 if ((isBlockedL && isBlockedR)) {
1462 double scalarl = 0.0;
1463 bool transpl =
false;
1464 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1465 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1466 double scalarr = 0.0;
1467 bool transpr =
false;
1468 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1469 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1470 double scalar = scalarl * scalarr;
1472 int numRows = blocked_opl->productRange()->numBlocks();
1473 int numCols = blocked_opr->productDomain()->numBlocks();
1474 int numMiddle = blocked_opl->productDomain()->numBlocks();
1476 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1478 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1479 Thyra::defaultBlockedLinearOp<double>();
1480 blocked_product->beginBlockFill(numRows, numCols);
1481 for (
int r = 0; r < numRows; ++r) {
1482 for (
int c = 0; c < numCols; ++c) {
1483 LinearOp product_rc =
1484 explicitMultiply(blocked_opl->getBlock(r, 0), blocked_opr->getBlock(0, c));
1485 for (
int m = 1; m < numMiddle; ++m) {
1486 LinearOp product_m =
1487 explicitMultiply(blocked_opl->getBlock(r, m), blocked_opr->getBlock(m, c));
1488 product_rc = explicitAdd(product_rc, product_m);
1490 blocked_product->setBlock(r, c, Thyra::scale(scalar, product_rc));
1493 blocked_product->endBlockFill();
1494 return blocked_product;
1498 if ((isBlockedL && !isBlockedR)) {
1499 double scalarl = 0.0;
1500 bool transpl =
false;
1501 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1502 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1503 double scalar = scalarl;
1505 int numRows = blocked_opl->productRange()->numBlocks();
1509 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1511 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1512 Thyra::defaultBlockedLinearOp<double>();
1513 blocked_product->beginBlockFill(numRows, numCols);
1514 for (
int r = 0; r < numRows; ++r) {
1515 LinearOp product_r = explicitMultiply(blocked_opl->getBlock(r, 0), opr);
1516 blocked_product->setBlock(r, 0, Thyra::scale(scalar, product_r));
1518 blocked_product->endBlockFill();
1519 return blocked_product;
1523 if ((!isBlockedL && isBlockedR)) {
1524 double scalarr = 0.0;
1525 bool transpr =
false;
1526 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1527 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1528 double scalar = scalarr;
1531 int numCols = blocked_opr->productDomain()->numBlocks();
1534 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1536 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1537 Thyra::defaultBlockedLinearOp<double>();
1538 blocked_product->beginBlockFill(numRows, numCols);
1539 for (
int c = 0; c < numCols; ++c) {
1540 LinearOp product_c = explicitMultiply(opl, blocked_opr->getBlock(0, c));
1541 blocked_product->setBlock(0, c, Thyra::scale(scalar, product_c));
1543 blocked_product->endBlockFill();
1544 return blocked_product;
1547 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1548 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1550 if (isTpetral && isTpetrar) {
1553 bool transpl =
false;
1554 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1555 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1557 bool transpr =
false;
1558 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1559 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1562 RCP<Thyra::LinearOpBase<ST>> explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1563 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
1564 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
1567 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1568 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1569 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOpl, transpl, *tCrsOpr, transpr,
1571 explicitCrsOp->resumeFill();
1572 explicitCrsOp->scale(scalarl * scalarr);
1573 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1574 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1575 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1579 }
else if (isTpetral && !isTpetrar) {
1583 bool transpl =
false;
1584 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1585 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1588 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpr =
1589 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opr,
true);
1590 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1591 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpr->getDiag(),
true);
1592 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr =
1593 rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
true);
1594 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1595 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1596 tCrsOpl, Tpetra::Import<LO, GO, NT>(tCrsOpl->getRowMap(), tCrsOpl->getRowMap()));
1598 explicitCrsOp->rightScale(*diagPtr);
1599 explicitCrsOp->resumeFill();
1600 explicitCrsOp->scale(scalarl);
1601 explicitCrsOp->fillComplete(tCrsOpl->getDomainMap(), tCrsOpl->getRangeMap());
1603 return Thyra::constTpetraLinearOp<ST, LO, GO, NT>(
1604 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1605 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()), explicitCrsOp);
1607 }
else if (!isTpetral && isTpetrar) {
1611 bool transpr =
false;
1612 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1613 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1615 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr;
1618 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpl =
1619 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opl);
1620 if (dOpl != Teuchos::null) {
1621 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1622 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpl->getDiag(),
true);
1623 diagPtr = rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
1627 else if (rcp_dynamic_cast<
const Thyra::ZeroLinearOpBase<ST>>(opl) != Teuchos::null) {
1628 diagPtr = rcp(
new Tpetra::Vector<ST, LO, GO, NT>(tCrsOpr->getRangeMap()));
1630 TEUCHOS_ASSERT(
false);
1632 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1633 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1634 tCrsOpr, Tpetra::Import<LO, GO, NT>(tCrsOpr->getRowMap(), tCrsOpr->getRowMap()));
1636 explicitCrsOp->leftScale(*diagPtr);
1637 explicitCrsOp->resumeFill();
1638 explicitCrsOp->scale(scalarr);
1639 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpr->getRangeMap());
1641 return Thyra::constTpetraLinearOp<ST, LO, GO, NT>(
1642 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1643 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()), explicitCrsOp);
1646 #ifdef TEKO_HAVE_EPETRA
1648 const LinearOp implicitOp = Thyra::multiply(opl, opr);
1651 RCP<Thyra::LinearOpTransformerBase<double>> prodTrans =
1652 Thyra::epetraExtDiagScalingTransformer();
1656 if (not prodTrans->isCompatible(*implicitOp))
1657 prodTrans = Thyra::epetraExtDiagScaledMatProdTransformer();
1660 const RCP<Thyra::LinearOpBase<double>> explicitOp = prodTrans->createOutputOp();
1661 prodTrans->transform(*implicitOp, explicitOp.ptr());
1662 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" * " +
1663 opr->getObjectLabel() +
" )");
1667 throw std::logic_error(
1668 "explicitMultiply is trying to use Epetra "
1669 "code, but TEKO_HAVE_EPETRA is disabled!");
1687 const ModifiableLinearOp explicitMultiply(
const LinearOp &opl,
const LinearOp &opr,
1688 const ModifiableLinearOp &destOp) {
1693 bool isBlockedL = isPhysicallyBlockedLinearOp(opl);
1694 bool isBlockedR = isPhysicallyBlockedLinearOp(opr);
1697 if ((isBlockedL && isBlockedR)) {
1698 double scalarl = 0.0;
1699 bool transpl =
false;
1700 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1701 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1702 double scalarr = 0.0;
1703 bool transpr =
false;
1704 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1705 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1706 double scalar = scalarl * scalarr;
1708 int numRows = blocked_opl->productRange()->numBlocks();
1709 int numCols = blocked_opr->productDomain()->numBlocks();
1710 int numMiddle = blocked_opl->productDomain()->numBlocks();
1712 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1714 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1715 Thyra::defaultBlockedLinearOp<double>();
1716 blocked_product->beginBlockFill(numRows, numCols);
1717 for (
int r = 0; r < numRows; ++r) {
1718 for (
int c = 0; c < numCols; ++c) {
1719 LinearOp product_rc =
1720 explicitMultiply(blocked_opl->getBlock(r, 0), blocked_opr->getBlock(0, c));
1721 for (
int m = 1; m < numMiddle; ++m) {
1722 LinearOp product_m =
1723 explicitMultiply(blocked_opl->getBlock(r, m), blocked_opr->getBlock(m, c));
1724 product_rc = explicitAdd(product_rc, product_m);
1726 blocked_product->setBlock(r, c, Thyra::scale(scalar, product_rc));
1729 blocked_product->endBlockFill();
1730 return blocked_product;
1734 if ((isBlockedL && !isBlockedR)) {
1735 double scalarl = 0.0;
1736 bool transpl =
false;
1737 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1738 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1739 double scalar = scalarl;
1741 int numRows = blocked_opl->productRange()->numBlocks();
1745 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1747 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1748 Thyra::defaultBlockedLinearOp<double>();
1749 blocked_product->beginBlockFill(numRows, numCols);
1750 for (
int r = 0; r < numRows; ++r) {
1751 LinearOp product_r = explicitMultiply(blocked_opl->getBlock(r, 0), opr);
1752 blocked_product->setBlock(r, 0, Thyra::scale(scalar, product_r));
1754 blocked_product->endBlockFill();
1755 return blocked_product;
1759 if ((!isBlockedL && isBlockedR)) {
1760 double scalarr = 0.0;
1761 bool transpr =
false;
1762 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1763 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1764 double scalar = scalarr;
1767 int numCols = blocked_opr->productDomain()->numBlocks();
1770 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1772 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_product =
1773 Thyra::defaultBlockedLinearOp<double>();
1774 blocked_product->beginBlockFill(numRows, numCols);
1775 for (
int c = 0; c < numCols; ++c) {
1776 LinearOp product_c = explicitMultiply(opl, blocked_opr->getBlock(0, c));
1777 blocked_product->setBlock(0, c, Thyra::scale(scalar, product_c));
1779 blocked_product->endBlockFill();
1780 return blocked_product;
1783 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1784 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1786 if (isTpetral && isTpetrar) {
1791 bool transpl =
false;
1792 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1793 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1795 bool transpr =
false;
1796 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1797 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1800 RCP<Thyra::LinearOpBase<ST>> explicitOp;
1801 if (destOp != Teuchos::null)
1802 explicitOp = destOp;
1804 explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
1805 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
1806 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
1809 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1810 Tpetra::createCrsMatrix<ST, LO, GO, NT>(tCrsOpl->getRowMap());
1811 Tpetra::MatrixMatrix::Multiply<ST, LO, GO, NT>(*tCrsOpl, transpl, *tCrsOpr, transpr,
1813 explicitCrsOp->resumeFill();
1814 explicitCrsOp->scale(scalarl * scalarr);
1815 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpl->getRangeMap());
1816 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1817 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
1821 }
else if (isTpetral && !isTpetrar) {
1825 bool transpl =
false;
1826 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
1827 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1830 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpr =
1831 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opr);
1832 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1833 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpr->getDiag(),
true);
1834 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr =
1835 rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
true);
1838 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1839 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1840 tCrsOpl, Tpetra::Import<LO, GO, NT>(tCrsOpl->getRowMap(), tCrsOpl->getRowMap()));
1841 explicitCrsOp->rightScale(*diagPtr);
1842 explicitCrsOp->resumeFill();
1843 explicitCrsOp->scale(scalarl);
1844 explicitCrsOp->fillComplete(tCrsOpl->getDomainMap(), tCrsOpl->getRangeMap());
1845 return Thyra::tpetraLinearOp<ST, LO, GO, NT>(
1846 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1847 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()), explicitCrsOp);
1849 }
else if (!isTpetral && isTpetrar) {
1853 bool transpr =
false;
1854 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
1855 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1858 RCP<const Thyra::DiagonalLinearOpBase<ST>> dOpl =
1859 rcp_dynamic_cast<
const Thyra::DiagonalLinearOpBase<ST>>(opl,
true);
1860 RCP<const Thyra::TpetraVector<ST, LO, GO, NT>> tPtr =
1861 rcp_dynamic_cast<
const Thyra::TpetraVector<ST, LO, GO, NT>>(dOpl->getDiag(),
true);
1862 RCP<const Tpetra::Vector<ST, LO, GO, NT>> diagPtr =
1863 rcp_dynamic_cast<
const Tpetra::Vector<ST, LO, GO, NT>>(tPtr->getConstTpetraVector(),
true);
1866 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
1867 Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST, LO, GO, NT>>(
1868 tCrsOpr, Tpetra::Import<LO, GO, NT>(tCrsOpr->getRowMap(), tCrsOpr->getRowMap()));
1869 explicitCrsOp->leftScale(*diagPtr);
1870 explicitCrsOp->resumeFill();
1871 explicitCrsOp->scale(scalarr);
1872 explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(), tCrsOpr->getRangeMap());
1873 return Thyra::tpetraLinearOp<ST, LO, GO, NT>(
1874 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
1875 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()), explicitCrsOp);
1878 #ifdef TEKO_HAVE_EPETRA
1880 const LinearOp implicitOp = Thyra::multiply(opl, opr);
1884 RCP<Thyra::LinearOpTransformerBase<double>> prodTrans =
1885 Thyra::epetraExtDiagScalingTransformer();
1889 if (not prodTrans->isCompatible(*implicitOp))
1890 prodTrans = Thyra::epetraExtDiagScaledMatProdTransformer();
1893 ModifiableLinearOp explicitOp;
1896 if (destOp == Teuchos::null)
1897 explicitOp = prodTrans->createOutputOp();
1899 explicitOp = destOp;
1902 prodTrans->transform(*implicitOp, explicitOp.ptr());
1905 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" * " +
1906 opr->getObjectLabel() +
" )");
1910 throw std::logic_error(
1911 "explicitMultiply is trying to use Epetra "
1912 "code, but TEKO_HAVE_EPETRA is disabled!");
1927 const LinearOp explicitAdd(
const LinearOp &opl_in,
const LinearOp &opr_in) {
1929 if (isPhysicallyBlockedLinearOp(opl_in) && isPhysicallyBlockedLinearOp(opr_in)) {
1930 double scalarl = 0.0;
1931 bool transpl =
false;
1932 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1933 getPhysicallyBlockedLinearOp(opl_in, &scalarl, &transpl);
1935 double scalarr = 0.0;
1936 bool transpr =
false;
1937 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1938 getPhysicallyBlockedLinearOp(opr_in, &scalarr, &transpr);
1940 int numRows = blocked_opl->productRange()->numBlocks();
1941 int numCols = blocked_opl->productDomain()->numBlocks();
1942 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numRows);
1943 TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == numCols);
1945 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_sum =
1946 Thyra::defaultBlockedLinearOp<double>();
1947 blocked_sum->beginBlockFill(numRows, numCols);
1948 for (
int r = 0; r < numRows; ++r)
1949 for (
int c = 0; c < numCols; ++c)
1950 blocked_sum->setBlock(r, c,
1951 explicitAdd(Thyra::scale(scalarl, blocked_opl->getBlock(r, c)),
1952 Thyra::scale(scalarr, blocked_opr->getBlock(r, c))));
1953 blocked_sum->endBlockFill();
1958 LinearOp opl = opl_in;
1959 LinearOp opr = opr_in;
1960 if (isPhysicallyBlockedLinearOp(opl_in)) {
1961 double scalarl = 0.0;
1962 bool transpl =
false;
1963 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
1964 getPhysicallyBlockedLinearOp(opl_in, &scalarl, &transpl);
1965 TEUCHOS_ASSERT(blocked_opl->productRange()->numBlocks() == 1);
1966 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == 1);
1967 opl = Thyra::scale(scalarl, blocked_opl->getBlock(0, 0));
1969 if (isPhysicallyBlockedLinearOp(opr_in)) {
1970 double scalarr = 0.0;
1971 bool transpr =
false;
1972 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
1973 getPhysicallyBlockedLinearOp(opr_in, &scalarr, &transpr);
1974 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == 1);
1975 TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == 1);
1976 opr = Thyra::scale(scalarr, blocked_opr->getBlock(0, 0));
1979 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1980 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1983 if (isZeroOp(opl)) {
1984 if (isZeroOp(opr))
return opr;
1987 bool transp =
false;
1988 auto crs_op = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalar, &transp);
1989 auto zero_crs = Tpetra::createCrsMatrix<ST, LO, GO, NT>(crs_op->getRowMap());
1990 zero_crs->fillComplete();
1991 opl = Thyra::constTpetraLinearOp<ST, LO, GO, NT>(
1992 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(crs_op->getRangeMap()),
1993 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(crs_op->getDomainMap()), zero_crs);
1996 return opr->clone();
1998 if (isZeroOp(opr)) {
2001 bool transp =
false;
2002 auto crs_op = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalar, &transp);
2003 auto zero_crs = Tpetra::createCrsMatrix<ST, LO, GO, NT>(crs_op->getRowMap());
2004 zero_crs->fillComplete();
2005 opr = Thyra::constTpetraLinearOp<ST, LO, GO, NT>(
2006 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(crs_op->getRangeMap()),
2007 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(crs_op->getDomainMap()), zero_crs);
2010 return opl->clone();
2013 if (isTpetral && isTpetrar) {
2018 bool transpl =
false;
2019 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
2020 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
2022 bool transpr =
false;
2023 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
2024 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
2027 RCP<Thyra::LinearOpBase<ST>> explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
2028 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
2029 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
2032 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp =
2033 Tpetra::MatrixMatrix::add<ST, LO, GO, NT>(scalarl, transpl, *tCrsOpl, scalarr, transpr,
2035 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
2036 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
2041 #ifdef TEKO_HAVE_EPETRA
2043 const LinearOp implicitOp = Thyra::add(opl, opr);
2046 const RCP<Thyra::LinearOpTransformerBase<double>> prodTrans = Thyra::epetraExtAddTransformer();
2049 const RCP<Thyra::LinearOpBase<double>> explicitOp = prodTrans->createOutputOp();
2050 prodTrans->transform(*implicitOp, explicitOp.ptr());
2051 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" + " +
2052 opr->getObjectLabel() +
" )");
2056 throw std::logic_error(
2057 "explicitAdd is trying to use Epetra "
2058 "code, but TEKO_HAVE_EPETRA is disabled!");
2075 const ModifiableLinearOp explicitAdd(
const LinearOp &opl_in,
const LinearOp &opr_in,
2076 const ModifiableLinearOp &destOp) {
2078 if (isPhysicallyBlockedLinearOp(opl_in) && isPhysicallyBlockedLinearOp(opr_in)) {
2079 double scalarl = 0.0;
2080 bool transpl =
false;
2081 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
2082 getPhysicallyBlockedLinearOp(opl_in, &scalarl, &transpl);
2084 double scalarr = 0.0;
2085 bool transpr =
false;
2086 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
2087 getPhysicallyBlockedLinearOp(opr_in, &scalarr, &transpr);
2089 int numRows = blocked_opl->productRange()->numBlocks();
2090 int numCols = blocked_opl->productDomain()->numBlocks();
2091 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numRows);
2092 TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == numCols);
2094 RCP<Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_sum =
2095 Teuchos::rcp_dynamic_cast<Thyra::DefaultBlockedLinearOp<double>>(destOp);
2096 if (blocked_sum.is_null()) {
2098 blocked_sum = Thyra::defaultBlockedLinearOp<double>();
2100 blocked_sum->beginBlockFill(numRows, numCols);
2101 for (
int r = 0; r < numRows; ++r) {
2102 for (
int c = 0; c < numCols; ++c) {
2104 explicitAdd(Thyra::scale(scalarl, blocked_opl->getBlock(r, c)),
2105 Thyra::scale(scalarr, blocked_opr->getBlock(r, c)), Teuchos::null);
2106 blocked_sum->setNonconstBlock(r, c, block);
2109 blocked_sum->endBlockFill();
2113 for (
int r = 0; r < numRows; ++r)
2114 for (
int c = 0; c < numCols; ++c)
2115 explicitAdd(Thyra::scale(scalarl, blocked_opl->getBlock(r, c)),
2116 Thyra::scale(scalarr, blocked_opr->getBlock(r, c)),
2117 blocked_sum->getNonconstBlock(r, c));
2123 LinearOp opl = opl_in;
2124 LinearOp opr = opr_in;
2126 if (isPhysicallyBlockedLinearOp(opl)) {
2127 double scalarl = 0.0;
2128 bool transpl =
false;
2129 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opl =
2130 getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
2131 TEUCHOS_ASSERT(blocked_opl->productRange()->numBlocks() == 1);
2132 TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == 1);
2133 opl = Thyra::scale(scalarl, blocked_opl->getBlock(0, 0));
2135 if (isPhysicallyBlockedLinearOp(opr)) {
2136 double scalarr = 0.0;
2137 bool transpr =
false;
2138 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_opr =
2139 getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
2140 TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == 1);
2141 TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == 1);
2142 opr = Thyra::scale(scalarr, blocked_opr->getBlock(0, 0));
2145 bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
2146 bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
2148 if (isTpetral && isTpetrar) {
2153 bool transpl =
false;
2154 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpl =
2155 Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
2157 bool transpr =
false;
2158 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOpr =
2159 Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
2162 RCP<Thyra::LinearOpBase<ST>> explicitOp;
2163 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> explicitCrsOp;
2164 if (!destOp.is_null()) {
2165 explicitOp = destOp;
2166 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tOp =
2167 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(destOp);
2170 rcp_dynamic_cast<Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getTpetraOperator());
2171 bool needNewTpetraMatrix =
2172 (explicitCrsOp.is_null()) || (tCrsOpl == explicitCrsOp) || (tCrsOpr == explicitCrsOp);
2173 if (!needNewTpetraMatrix) {
2176 Tpetra::MatrixMatrix::Add<ST, LO, GO, NT>(*tCrsOpl, transpl, scalarl, *tCrsOpr, transpr,
2177 scalarr, explicitCrsOp);
2178 }
catch (std::logic_error &e) {
2179 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
2180 *out <<
"*** THROWN EXCEPTION ***\n";
2181 *out << e.what() << std::endl;
2182 *out <<
"************************\n";
2183 *out <<
"Teko: explicitAdd unable to reuse existing operator. Creating new operator.\n"
2185 needNewTpetraMatrix =
true;
2188 if (needNewTpetraMatrix)
2190 explicitCrsOp = Tpetra::MatrixMatrix::add<ST, LO, GO, NT>(scalarl, transpl, *tCrsOpl,
2191 scalarr, transpr, *tCrsOpr);
2193 explicitOp = rcp(
new Thyra::TpetraLinearOp<ST, LO, GO, NT>());
2195 explicitCrsOp = Tpetra::MatrixMatrix::add<ST, LO, GO, NT>(scalarl, transpl, *tCrsOpl, scalarr,
2198 RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tExplicitOp =
2199 rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(explicitOp);
2201 tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getRangeMap()),
2202 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(explicitCrsOp->getDomainMap()),
2207 #ifdef TEKO_HAVE_EPETRA
2209 const LinearOp implicitOp = Thyra::add(opl, opr);
2212 const RCP<Thyra::LinearOpTransformerBase<double>> prodTrans = Thyra::epetraExtAddTransformer();
2215 RCP<Thyra::LinearOpBase<double>> explicitOp;
2216 if (destOp != Teuchos::null)
2217 explicitOp = destOp;
2219 explicitOp = prodTrans->createOutputOp();
2222 prodTrans->transform(*implicitOp, explicitOp.ptr());
2223 explicitOp->setObjectLabel(
"explicit( " + opl->getObjectLabel() +
" + " +
2224 opr->getObjectLabel() +
" )");
2228 throw std::logic_error(
2229 "explicitAdd is trying to use Epetra "
2230 "code, but TEKO_HAVE_EPETRA is disabled!");
2239 const ModifiableLinearOp explicitSum(
const LinearOp &op,
const ModifiableLinearOp &destOp) {
2240 #ifdef TEKO_HAVE_EPETRA
2242 const RCP<const Epetra_CrsMatrix> epetraOp =
2243 rcp_dynamic_cast<
const Epetra_CrsMatrix>(get_Epetra_Operator(*op),
true);
2245 if (destOp == Teuchos::null) {
2246 Teuchos::RCP<Epetra_Operator> epetraDest = Teuchos::rcp(
new Epetra_CrsMatrix(*epetraOp));
2248 return Thyra::nonconstEpetraLinearOp(epetraDest);
2251 const RCP<Epetra_CrsMatrix> epetraDest =
2252 rcp_dynamic_cast<Epetra_CrsMatrix>(get_Epetra_Operator(*destOp),
true);
2254 EpetraExt::MatrixMatrix::Add(*epetraOp,
false, 1.0, *epetraDest, 1.0);
2258 throw std::logic_error(
2259 "explicitSum is trying to use Epetra "
2260 "code, but TEKO_HAVE_EPETRA is disabled!");
2264 const LinearOp explicitTranspose(
const LinearOp &op) {
2265 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2266 RCP<const Thyra::TpetraLinearOp<ST, LO, GO, NT>> tOp =
2267 rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op,
true);
2268 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp =
2269 rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
2272 Tpetra::RowMatrixTransposer<ST, LO, GO, NT> transposer(tCrsOp);
2273 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> transOp = transposer.createTranspose();
2275 return Thyra::tpetraLinearOp<ST, LO, GO, NT>(
2276 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(transOp->getRangeMap()),
2277 Thyra::tpetraVectorSpace<ST, LO, GO, NT>(transOp->getDomainMap()), transOp);
2280 #ifdef TEKO_HAVE_EPETRA
2281 RCP<const Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
2282 TEUCHOS_TEST_FOR_EXCEPTION(eOp == Teuchos::null, std::logic_error,
2283 "Teko::explicitTranspose Not an Epetra_Operator");
2284 RCP<const Epetra_RowMatrix> eRowMatrixOp =
2285 Teuchos::rcp_dynamic_cast<
const Epetra_RowMatrix>(eOp);
2286 TEUCHOS_TEST_FOR_EXCEPTION(eRowMatrixOp == Teuchos::null, std::logic_error,
2287 "Teko::explicitTranspose Not an Epetra_RowMatrix");
2290 EpetraExt::RowMatrix_Transpose tranposeOp;
2291 Epetra_RowMatrix &eMat = tranposeOp(const_cast<Epetra_RowMatrix &>(*eRowMatrixOp));
2295 Teuchos::RCP<Epetra_CrsMatrix> crsMat =
2296 Teuchos::rcp(
new Epetra_CrsMatrix(dynamic_cast<Epetra_CrsMatrix &>(eMat)));
2298 return Thyra::epetraLinearOp(crsMat);
2300 throw std::logic_error(
2301 "explicitTranspose is trying to use Epetra "
2302 "code, but TEKO_HAVE_EPETRA is disabled!");
2307 const LinearOp explicitScale(
double scalar,
const LinearOp &op) {
2308 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2309 RCP<const Thyra::TpetraLinearOp<ST, LO, GO, NT>> tOp =
2310 rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op,
true);
2311 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp =
2312 rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
2314 auto crsOpNew = rcp(
new Tpetra::CrsMatrix<ST, LO, GO, NT>(*tCrsOp, Teuchos::Copy));
2315 crsOpNew->scale(scalar);
2316 return Thyra::tpetraLinearOp<ST, LO, GO, NT>(
2317 Thyra::createVectorSpace<ST, LO, GO, NT>(crsOpNew->getRangeMap()),
2318 Thyra::createVectorSpace<ST, LO, GO, NT>(crsOpNew->getDomainMap()), crsOpNew);
2320 #ifdef TEKO_HAVE_EPETRA
2321 RCP<const Thyra::EpetraLinearOp> eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op,
true);
2322 RCP<const Epetra_CrsMatrix> eCrsOp =
2323 rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
2324 Teuchos::RCP<Epetra_CrsMatrix> crsMat = Teuchos::rcp(
new Epetra_CrsMatrix(*eCrsOp));
2326 crsMat->Scale(scalar);
2328 return Thyra::epetraLinearOp(crsMat);
2330 throw std::logic_error(
2331 "explicitScale is trying to use Epetra "
2332 "code, but TEKO_HAVE_EPETRA is disabled!");
2337 double frobeniusNorm(
const LinearOp &op_in) {
2339 double scalar = 1.0;
2342 if (isPhysicallyBlockedLinearOp(op_in)) {
2343 bool transp =
false;
2344 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_op =
2345 getPhysicallyBlockedLinearOp(op_in, &scalar, &transp);
2346 TEUCHOS_ASSERT(blocked_op->productRange()->numBlocks() == 1);
2347 TEUCHOS_ASSERT(blocked_op->productDomain()->numBlocks() == 1);
2348 op = blocked_op->getBlock(0, 0);
2352 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2353 const RCP<const Thyra::TpetraLinearOp<ST, LO, GO, NT>> tOp =
2354 rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op);
2355 const RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> crsOp =
2356 rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
2358 return crsOp->getFrobeniusNorm();
2360 #ifdef TEKO_HAVE_EPETRA
2361 const RCP<const Epetra_Operator> epOp = Thyra::get_Epetra_Operator(*op);
2362 const RCP<const Epetra_CrsMatrix> crsOp = rcp_dynamic_cast<
const Epetra_CrsMatrix>(epOp,
true);
2363 return crsOp->NormFrobenius();
2365 throw std::logic_error(
2366 "frobeniusNorm is trying to use Epetra "
2367 "code, but TEKO_HAVE_EPETRA is disabled!");
2372 double oneNorm(
const LinearOp &op) {
2373 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2374 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::logic_error,
2375 "One norm not currently implemented for Tpetra matrices");
2378 #ifdef TEKO_HAVE_EPETRA
2379 const RCP<const Epetra_Operator> epOp = Thyra::get_Epetra_Operator(*op);
2380 const RCP<const Epetra_CrsMatrix> crsOp = rcp_dynamic_cast<
const Epetra_CrsMatrix>(epOp,
true);
2381 return crsOp->NormOne();
2383 throw std::logic_error(
2384 "oneNorm is trying to use Epetra "
2385 "code, but TEKO_HAVE_EPETRA is disabled!");
2390 double infNorm(
const LinearOp &op) {
2391 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2393 bool transp =
false;
2394 RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> tCrsOp =
2395 Teko::TpetraHelpers::getTpetraCrsMatrix(op, &scalar, &transp);
2398 const RCP<Tpetra::Vector<ST, LO, GO, NT>> ptrDiag =
2399 Tpetra::createVector<ST, LO, GO, NT>(tCrsOp->getRowMap());
2400 Tpetra::Vector<ST, LO, GO, NT> &diag = *ptrDiag;
2403 diag.putScalar(0.0);
2404 for (LO i = 0; i < (LO)tCrsOp->getLocalNumRows(); i++) {
2405 LO numEntries = tCrsOp->getNumEntriesInLocalRow(i);
2406 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::local_inds_host_view_type indices;
2407 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::values_host_view_type values;
2408 tCrsOp->getLocalRowView(i, indices, values);
2411 for (LO j = 0; j < numEntries; j++) diag.sumIntoLocalValue(i, std::abs(values(j)));
2413 return diag.normInf() * scalar;
2416 #ifdef TEKO_HAVE_EPETRA
2417 const RCP<const Epetra_Operator> epOp = Thyra::get_Epetra_Operator(*op);
2418 const RCP<const Epetra_CrsMatrix> crsOp = rcp_dynamic_cast<
const Epetra_CrsMatrix>(epOp,
true);
2419 return crsOp->NormInf();
2421 throw std::logic_error(
2422 "infNorm is trying to use Epetra "
2423 "code, but TEKO_HAVE_EPETRA is disabled!");
2428 const LinearOp buildDiagonal(
const MultiVector &src,
const std::string &lbl) {
2429 RCP<Thyra::VectorBase<double>> dst = Thyra::createMember(src->range());
2430 Thyra::copy(*src->col(0), dst.ptr());
2432 return Thyra::diagonal<double>(dst, lbl);
2435 const LinearOp buildInvDiagonal(
const MultiVector &src,
const std::string &lbl) {
2436 const RCP<const Thyra::VectorBase<double>> srcV = src->col(0);
2437 RCP<Thyra::VectorBase<double>> dst = Thyra::createMember(srcV->range());
2438 Thyra::reciprocal<double>(*srcV, dst.ptr());
2440 return Thyra::diagonal<double>(dst, lbl);
2444 BlockedMultiVector buildBlockedMultiVector(
const std::vector<MultiVector> &mvv) {
2445 Teuchos::Array<MultiVector> mvA;
2446 Teuchos::Array<VectorSpace> vsA;
2449 std::vector<MultiVector>::const_iterator itr;
2450 for (itr = mvv.begin(); itr != mvv.end(); ++itr) {
2451 mvA.push_back(*itr);
2452 vsA.push_back((*itr)->range());
2456 const RCP<const Thyra::DefaultProductVectorSpace<double>> vs =
2457 Thyra::productVectorSpace<double>(vsA);
2459 return Thyra::defaultProductMultiVector<double>(vs, mvA);
2472 Teuchos::RCP<Thyra::VectorBase<double>> indicatorVector(
const std::vector<int> &indices,
2473 const VectorSpace &vs,
double onValue,
2480 RCP<Thyra::VectorBase<double>> v = Thyra::createMember<double>(vs);
2481 Thyra::put_scalar<double>(offValue, v.ptr());
2484 for (std::size_t i = 0; i < indices.size(); i++)
2485 Thyra::set_ele<double>(indices[i], onValue, v.ptr());
2514 double computeSpectralRad(
const RCP<
const Thyra::LinearOpBase<double>> &A,
double tol,
2515 bool isHermitian,
int numBlocks,
int restart,
int verbosity) {
2516 typedef Thyra::LinearOpBase<double> OP;
2517 typedef Thyra::MultiVectorBase<double> MV;
2519 int startVectors = 1;
2522 const RCP<MV> ivec = Thyra::createMember(A->domain());
2523 Thyra::randomize(-1.0, 1.0, ivec.ptr());
2525 RCP<Anasazi::BasicEigenproblem<double, MV, OP>> eigProb =
2526 rcp(
new Anasazi::BasicEigenproblem<double, MV, OP>(A, ivec));
2528 eigProb->setHermitian(isHermitian);
2531 if (not eigProb->setProblem()) {
2533 return Teuchos::ScalarTraits<double>::nan();
2537 std::string which(
"LM");
2541 Teuchos::ParameterList MyPL;
2542 MyPL.set(
"Verbosity", verbosity);
2543 MyPL.set(
"Which", which);
2544 MyPL.set(
"Block Size", startVectors);
2545 MyPL.set(
"Num Blocks", numBlocks);
2546 MyPL.set(
"Maximum Restarts", restart);
2547 MyPL.set(
"Convergence Tolerance", tol);
2555 Anasazi::BlockKrylovSchurSolMgr<double, MV, OP> MyBlockKrylovSchur(eigProb, MyPL);
2558 Anasazi::ReturnType solverreturn = MyBlockKrylovSchur.solve();
2560 if (solverreturn == Anasazi::Unconverged) {
2561 double real = MyBlockKrylovSchur.getRitzValues().begin()->realpart;
2562 double comp = MyBlockKrylovSchur.getRitzValues().begin()->imagpart;
2564 return -std::abs(std::sqrt(real * real + comp * comp));
2569 double real = eigProb->getSolution().Evals.begin()->realpart;
2570 double comp = eigProb->getSolution().Evals.begin()->imagpart;
2572 return std::abs(std::sqrt(real * real + comp * comp));
2602 double computeSmallestMagEig(
const RCP<
const Thyra::LinearOpBase<double>> &A,
double tol,
2603 bool isHermitian,
int numBlocks,
int restart,
int verbosity) {
2604 typedef Thyra::LinearOpBase<double> OP;
2605 typedef Thyra::MultiVectorBase<double> MV;
2607 int startVectors = 1;
2610 const RCP<MV> ivec = Thyra::createMember(A->domain());
2611 Thyra::randomize(-1.0, 1.0, ivec.ptr());
2613 RCP<Anasazi::BasicEigenproblem<double, MV, OP>> eigProb =
2614 rcp(
new Anasazi::BasicEigenproblem<double, MV, OP>(A, ivec));
2616 eigProb->setHermitian(isHermitian);
2619 if (not eigProb->setProblem()) {
2621 return Teuchos::ScalarTraits<double>::nan();
2625 std::string which(
"SM");
2628 Teuchos::ParameterList MyPL;
2629 MyPL.set(
"Verbosity", verbosity);
2630 MyPL.set(
"Which", which);
2631 MyPL.set(
"Block Size", startVectors);
2632 MyPL.set(
"Num Blocks", numBlocks);
2633 MyPL.set(
"Maximum Restarts", restart);
2634 MyPL.set(
"Convergence Tolerance", tol);
2642 Anasazi::BlockKrylovSchurSolMgr<double, MV, OP> MyBlockKrylovSchur(eigProb, MyPL);
2645 Anasazi::ReturnType solverreturn = MyBlockKrylovSchur.solve();
2647 if (solverreturn == Anasazi::Unconverged) {
2649 return -std::abs(MyBlockKrylovSchur.getRitzValues().begin()->realpart);
2652 return std::abs(eigProb->getSolution().Evals.begin()->realpart);
2664 ModifiableLinearOp getDiagonalOp(
const Teko::LinearOp &A,
const DiagonalType &dt) {
2666 case Diagonal:
return getDiagonalOp(A);
2667 case Lumped:
return getLumpedMatrix(A);
2668 case AbsRowSum:
return getAbsRowSumMatrix(A);
2670 default: TEUCHOS_TEST_FOR_EXCEPT(
true);
2673 return Teuchos::null;
2684 ModifiableLinearOp getInvDiagonalOp(
const Teko::LinearOp &A,
const Teko::DiagonalType &dt) {
2686 case Diagonal:
return getInvDiagonalOp(A);
2687 case Lumped:
return getInvLumpedMatrix(A);
2688 case AbsRowSum:
return getAbsRowSumInvMatrix(A);
2690 default: TEUCHOS_TEST_FOR_EXCEPT(
true);
2693 return Teuchos::null;
2702 std::string getDiagonalName(
const DiagonalType &dt) {
2704 case Diagonal:
return "Diagonal";
2705 case Lumped:
return "Lumped";
2706 case AbsRowSum:
return "AbsRowSum";
2707 case NotDiag:
return "NotDiag";
2708 case BlkDiag:
return "BlkDiag";
2722 DiagonalType getDiagonalType(std::string name) {
2723 if (name ==
"Diagonal")
return Diagonal;
2724 if (name ==
"Lumped")
return Lumped;
2725 if (name ==
"AbsRowSum")
return AbsRowSum;
2726 if (name ==
"BlkDiag")
return BlkDiag;
2731 #ifdef TEKO_HAVE_EPETRA
2732 LinearOp probe(Teuchos::RCP<const Epetra_CrsGraph> &G,
const LinearOp &Op) {
2733 #ifdef Teko_ENABLE_Isorropia
2734 Teuchos::ParameterList probeList;
2735 Prober prober(G, probeList,
true);
2736 Teuchos::RCP<Epetra_CrsMatrix> Mat = rcp(
new Epetra_CrsMatrix(Copy, *G));
2738 prober.probe(Mwrap, *Mat);
2739 return Thyra::epetraLinearOp(Mat);
2743 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::runtime_error,
"Probe requires Isorropia");
2748 double norm_1(
const MultiVector &v, std::size_t col) {
2749 Teuchos::Array<double> n(v->domain()->dim());
2750 Thyra::norms_1<double>(*v, n);
2755 double norm_2(
const MultiVector &v, std::size_t col) {
2756 Teuchos::Array<double> n(v->domain()->dim());
2757 Thyra::norms_2<double>(*v, n);
2762 #ifdef TEKO_HAVE_EPETRA
2763 void putScalar(
const ModifiableLinearOp &op,
double scalar) {
2766 RCP<Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
2769 RCP<Epetra_CrsMatrix> eCrsOp = rcp_dynamic_cast<Epetra_CrsMatrix>(eOp,
true);
2771 eCrsOp->PutScalar(scalar);
2772 }
catch (std::exception &e) {
2773 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
2775 *out <<
"Teko: putScalar requires an Epetra_CrsMatrix\n";
2776 *out <<
" Could not extract an Epetra_Operator from a \"" << op->description() << std::endl;
2778 *out <<
" Could not cast an Epetra_Operator to a Epetra_CrsMatrix\n";
2780 *out <<
"*** THROWN EXCEPTION ***\n";
2781 *out << e.what() << std::endl;
2782 *out <<
"************************\n";
2789 void clipLower(MultiVector &v,
double lowerBound) {
2791 using Teuchos::rcp_dynamic_cast;
2797 for (Thyra::Ordinal i = 0; i < v->domain()->dim(); i++) {
2798 RCP<Thyra::SpmdVectorBase<double>> spmdVec =
2799 rcp_dynamic_cast<Thyra::SpmdVectorBase<double>>(v->col(i),
true);
2801 Teuchos::ArrayRCP<double> values;
2803 spmdVec->getNonconstLocalData(Teuchos::ptrFromRef(values));
2804 for (Teuchos::ArrayRCP<double>::size_type j = 0; j < values.size(); j++) {
2805 if (values[j] < lowerBound) values[j] = lowerBound;
2810 void clipUpper(MultiVector &v,
double upperBound) {
2812 using Teuchos::rcp_dynamic_cast;
2817 for (Thyra::Ordinal i = 0; i < v->domain()->dim(); i++) {
2818 RCP<Thyra::SpmdVectorBase<double>> spmdVec =
2819 rcp_dynamic_cast<Thyra::SpmdVectorBase<double>>(v->col(i),
true);
2821 Teuchos::ArrayRCP<double> values;
2823 spmdVec->getNonconstLocalData(Teuchos::ptrFromRef(values));
2824 for (Teuchos::ArrayRCP<double>::size_type j = 0; j < values.size(); j++) {
2825 if (values[j] > upperBound) values[j] = upperBound;
2830 void replaceValue(MultiVector &v,
double currentValue,
double newValue) {
2832 using Teuchos::rcp_dynamic_cast;
2837 for (Thyra::Ordinal i = 0; i < v->domain()->dim(); i++) {
2838 RCP<Thyra::SpmdVectorBase<double>> spmdVec =
2839 rcp_dynamic_cast<Thyra::SpmdVectorBase<double>>(v->col(i),
true);
2841 Teuchos::ArrayRCP<double> values;
2843 spmdVec->getNonconstLocalData(Teuchos::ptrFromRef(values));
2844 for (Teuchos::ArrayRCP<double>::size_type j = 0; j < values.size(); j++) {
2845 if (values[j] == currentValue) values[j] = newValue;
2850 void columnAverages(
const MultiVector &v, std::vector<double> &averages) {
2851 averages.resize(v->domain()->dim());
2854 Thyra::sums<double>(*v, averages);
2857 Thyra::Ordinal rows = v->range()->dim();
2858 for (std::size_t i = 0; i < averages.size(); i++) averages[i] = averages[i] / rows;
2861 double average(
const MultiVector &v) {
2862 Thyra::Ordinal rows = v->range()->dim();
2863 Thyra::Ordinal cols = v->domain()->dim();
2865 std::vector<double> averages;
2866 columnAverages(v, averages);
2869 for (std::size_t i = 0; i < averages.size(); i++) sum += averages[i] * rows;
2871 return sum / (rows * cols);
2874 bool isPhysicallyBlockedLinearOp(
const LinearOp &op) {
2876 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> pblo =
2877 rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(op);
2878 if (!pblo.is_null())
return true;
2882 Thyra::EOpTransp transp = Thyra::NOTRANS;
2883 RCP<const Thyra::LinearOpBase<ST>> wrapped_op;
2884 Thyra::unwrap(op, &scalar, &transp, &wrapped_op);
2885 pblo = rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(wrapped_op);
2886 if (!pblo.is_null())
return true;
2891 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> getPhysicallyBlockedLinearOp(
2892 const LinearOp &op, ST *scalar,
bool *transp) {
2894 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> pblo =
2895 rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(op);
2896 if (!pblo.is_null()) {
2903 RCP<const Thyra::LinearOpBase<ST>> wrapped_op;
2904 Thyra::EOpTransp eTransp = Thyra::NOTRANS;
2905 Thyra::unwrap(op, scalar, &eTransp, &wrapped_op);
2906 pblo = rcp_dynamic_cast<
const Thyra::PhysicallyBlockedLinearOpBase<double>>(wrapped_op,
true);
2907 if (!pblo.is_null()) {
2909 if (eTransp == Thyra::NOTRANS) *transp =
false;
2913 return Teuchos::null;
2916 std::string formatBlockName(
const std::string &prefix,
int i,
int j,
int nrow) {
2917 unsigned digits = 0;
2918 auto blockId = nrow - 1;
2924 std::ostringstream ss;
2925 ss << prefix <<
"_";
2926 ss << std::setfill(
'0') << std::setw(digits) << i;
2928 ss << std::setfill(
'0') << std::setw(digits) << j;
2933 void writeMatrix(
const std::string &filename,
const Teko::LinearOp &op) {
2935 using Teuchos::rcp_dynamic_cast;
2936 #ifdef TEKO_HAVE_EPETRA
2937 const RCP<const Thyra::EpetraLinearOp> eOp = rcp_dynamic_cast<
const Thyra::EpetraLinearOp>(op);
2940 if (Teko::TpetraHelpers::isTpetraLinearOp(op)) {
2941 const RCP<const Thyra::TpetraLinearOp<ST, LO, GO, NT>> tOp =
2942 rcp_dynamic_cast<
const Thyra::TpetraLinearOp<ST, LO, GO, NT>>(op);
2943 const RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>> crsOp =
2944 rcp_dynamic_cast<
const Tpetra::CrsMatrix<ST, LO, GO, NT>>(tOp->getConstTpetraOperator(),
2946 using Writer = Tpetra::MatrixMarket::Writer<Tpetra::CrsMatrix<ST, LO, GO, NT>>;
2947 Writer::writeMapFile((
"rowmap_" + filename).c_str(), *(crsOp->getRowMap()));
2948 Writer::writeMapFile((
"colmap_" + filename).c_str(), *(crsOp->getColMap()));
2949 Writer::writeMapFile((
"domainmap_" + filename).c_str(), *(crsOp->getDomainMap()));
2950 Writer::writeMapFile((
"rangemap_" + filename).c_str(), *(crsOp->getRangeMap()));
2951 Writer::writeSparseFile(filename.c_str(), crsOp);
2953 #ifdef TEKO_HAVE_EPETRA
2954 else if (eOp != Teuchos::null) {
2955 const RCP<const Epetra_CrsMatrix> crsOp =
2956 rcp_dynamic_cast<
const Epetra_CrsMatrix>(eOp->epetra_op(),
true);
2957 EpetraExt::BlockMapToMatrixMarketFile((
"rowmap_" + filename).c_str(), crsOp->RowMap());
2958 EpetraExt::BlockMapToMatrixMarketFile((
"colmap_" + filename).c_str(), crsOp->ColMap());
2959 EpetraExt::BlockMapToMatrixMarketFile((
"domainmap_" + filename).c_str(), crsOp->DomainMap());
2960 EpetraExt::BlockMapToMatrixMarketFile((
"rangemap_" + filename).c_str(), crsOp->RangeMap());
2961 EpetraExt::RowMatrixToMatrixMarketFile(filename.c_str(), *crsOp);
2964 else if (isPhysicallyBlockedLinearOp(op)) {
2965 double scalar = 0.0;
2966 bool transp =
false;
2967 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double>> blocked_op =
2968 getPhysicallyBlockedLinearOp(op, &scalar, &transp);
2970 int numRows = blocked_op->productRange()->numBlocks();
2971 int numCols = blocked_op->productDomain()->numBlocks();
2973 for (
int r = 0; r < numRows; ++r)
2974 for (
int c = 0; c < numCols; ++c) {
2975 auto block = Teko::explicitScale(scalar, blocked_op->getBlock(r, c));
2976 if (transp) block = Teko::explicitTranspose(block);
2977 writeMatrix(formatBlockName(filename, r, c, numRows), block);
2980 TEUCHOS_ASSERT(
false);
Implements the Epetra_Operator interface with a Thyra LinearOperator. This enables the use of absrtac...