MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_SchurComplementFactory_def.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MueLu: A package for multigrid based preconditioning
4//
5// Copyright 2012 NTESS and the MueLu contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef MUELU_SCHURCOMPLEMENTFACTORY_DEF_HPP_
11#define MUELU_SCHURCOMPLEMENTFACTORY_DEF_HPP_
12
13#include <Xpetra_BlockedCrsMatrix.hpp>
14#include <Xpetra_MultiVectorFactory.hpp>
15#include <Xpetra_VectorFactory.hpp>
16#include <Xpetra_MatrixFactory.hpp>
17#include <Xpetra_Matrix.hpp>
18#include <Xpetra_MatrixMatrix.hpp>
19#include <Xpetra_TripleMatrixMultiply.hpp>
20#include <Xpetra_CrsMatrixWrap.hpp>
21#include <Xpetra_CrsMatrix.hpp>
22
23#include "MueLu_Level.hpp"
24#include "MueLu_Monitor.hpp"
26
27namespace MueLu {
28
29template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
31 RCP<ParameterList> validParamList = rcp(new ParameterList());
32
33 const SC one = Teuchos::ScalarTraits<SC>::one();
34
35 validParamList->set<RCP<const FactoryBase>>("A", NoFactory::getRCP(), "Generating factory of the matrix A used for building Schur complement (must be a 2x2 blocked operator)");
36 validParamList->set<RCP<const FactoryBase>>("Ainv", Teuchos::null, "Generating factory of the inverse matrix used in the Schur complement");
37
38 validParamList->set<SC>("omega", one, "Scaling parameter in S = A(1,1) - 1/omega A(1,0) Ainv A(0,1)");
39
40 return validParamList;
41}
42
43template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
45 Input(currentLevel, "A");
46
47 // Get default or user-given inverse approximation factory
48 RCP<const FactoryBase> AinvFact = GetFactory("Ainv");
49 currentLevel.DeclareInput("Ainv", AinvFact.get(), this);
50}
51
52template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
54 FactoryMonitor m(*this, "Build", currentLevel);
55
56 RCP<Matrix> A = Get<RCP<Matrix>>(currentLevel, "A");
57 RCP<BlockedCrsMatrix> bA = rcp_dynamic_cast<BlockedCrsMatrix>(A);
58
59 TEUCHOS_TEST_FOR_EXCEPTION(bA.is_null(), Exceptions::BadCast,
60 "MueLu::SchurComplementFactory::Build: input matrix A is not of type BlockedCrsMatrix!");
61 TEUCHOS_TEST_FOR_EXCEPTION(bA->Rows() != 2 || bA->Cols() != 2, Exceptions::RuntimeError,
62 "MueLu::SchurComplementFactory::Build: input matrix A is a " << bA->Rows() << "x" << bA->Cols() << " block matrix. We expect a 2x2 blocked operator.");
63
64 // Calculate Schur Complement
65 RCP<Matrix> Ainv = currentLevel.Get<RCP<Matrix>>("Ainv", this->GetFactory("Ainv").get());
66 RCP<Matrix> S = ComputeSchurComplement(bA, Ainv);
67
68 GetOStream(Statistics1) << "S has " << S->getGlobalNumRows() << "x" << S->getGlobalNumCols() << " rows and columns." << std::endl;
69
70 // NOTE: "A" generated by this factory is actually the Schur complement
71 // matrix, but it is required as all smoothers expect "A"
72 Set(currentLevel, "A", S);
73}
74
75template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
76RCP<Xpetra::Matrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>>
78 using STS = Teuchos::ScalarTraits<SC>;
79 const SC zero = STS::zero(), one = STS::one();
80
81 RCP<Matrix> A01 = bA->getMatrix(0, 1);
82 RCP<Matrix> A10 = bA->getMatrix(1, 0);
83 RCP<Matrix> A11 = bA->getMatrix(1, 1);
84
85 RCP<BlockedCrsMatrix> bA01 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A01);
86 const bool isBlocked = (bA01 == Teuchos::null ? false : true);
87
88 const ParameterList& pL = GetParameterList();
89 const SC omega = pL.get<Scalar>("omega");
90
91 TEUCHOS_TEST_FOR_EXCEPTION(omega == zero, Exceptions::RuntimeError,
92 "MueLu::SchurComplementFactory::Build: Scaling parameter omega must not be zero to avoid division by zero.");
93
94 RCP<Matrix> S = Teuchos::null; // Schur complement
95 RCP<Matrix> D = Teuchos::null; // temporary result for A10*Ainv*A01
96
97 // only if the off-diagonal blocks A10 and A01 are non-zero we have to do the MM multiplication
98 if (A01.is_null() == false && A10.is_null() == false) {
99 // scale with -1/omega
100 Ainv->scale(Teuchos::as<Scalar>(-one / omega));
101
102 // build Schur complement operator
103 if (!isBlocked) {
104 RCP<ParameterList> myparams = rcp(new ParameterList);
105 myparams->set("compute global constants", true);
106
107 // -1/omega*Ainv*A01
108 TEUCHOS_TEST_FOR_EXCEPTION(A01->getRangeMap()->isSameAs(*(Ainv->getDomainMap())) == false, Exceptions::RuntimeError,
109 "MueLu::SchurComplementFactory::Build: RangeMap of A01 and domain map of Ainv are not the same.");
110 RCP<Matrix> C = MatrixMatrix::Multiply(*Ainv, false, *A01, false, GetOStream(Statistics2), true, true, std::string("SchurComplementFactory"), myparams);
111
112 // -1/omega*A10*Ainv*A01
113 TEUCHOS_TEST_FOR_EXCEPTION(A01->getRangeMap()->isSameAs(*(A10->getDomainMap())) == false, Exceptions::RuntimeError,
114 "MueLu::SchurComplementFactory::Build: RangeMap of A10 and domain map A01 are not the same.");
115 D = MatrixMatrix::Multiply(*A10, false, *C, false, GetOStream(Statistics2), true, true, std::string("SchurComplementFactory"), myparams);
116 } else {
117 // nested blocking
118 auto bA10 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A10);
119 auto bAinv = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(Ainv);
120 TEUCHOS_TEST_FOR_EXCEPTION(bAinv == Teuchos::null, Exceptions::RuntimeError,
121 "MueLu::SchurComplementFactory::Build: Casting Ainv to BlockedCrsMatrix not possible.");
122
123 // -1/omega*bAinv*bA01
124 TEUCHOS_TEST_FOR_EXCEPTION(bA01->Rows() != bAinv->Cols(), Exceptions::RuntimeError,
125 "MueLu::SchurComplementFactory::Build: Block rows and cols of bA01 and bAinv are not compatible.");
126 RCP<BlockedCrsMatrix> C = MatrixMatrix::TwoMatrixMultiplyBlock(*bAinv, false, *bA01, false, GetOStream(Statistics2));
127
128 // -1/omega*A10*Ainv*A01
129 TEUCHOS_TEST_FOR_EXCEPTION(bA10->Rows() != bA01->Cols(), Exceptions::RuntimeError,
130 "MueLu::SchurComplementFactory::Build: Block rows and cols of bA10 and bA01 are not compatible.");
131 D = MatrixMatrix::TwoMatrixMultiplyBlock(*bA10, false, *C, false, GetOStream(Statistics2));
132 }
133 if (!A11.is_null()) {
134 MatrixMatrix::TwoMatrixAdd(*A11, false, one, *D, false, one, S, GetOStream(Statistics2));
135 S->fillComplete();
136
137 TEUCHOS_TEST_FOR_EXCEPTION(A11->getRangeMap()->isSameAs(*(S->getRangeMap())) == false, Exceptions::RuntimeError,
138 "MueLu::SchurComplementFactory::Build: RangeMap of A11 and S are not the same.");
139 TEUCHOS_TEST_FOR_EXCEPTION(A11->getDomainMap()->isSameAs(*(S->getDomainMap())) == false, Exceptions::RuntimeError,
140 "MueLu::SchurComplementFactory::Build: DomainMap of A11 and S are not the same.");
141 } else {
142 S = MatrixFactory::BuildCopy(D);
143 }
144 } else {
145 if (!A11.is_null()) {
146 S = MatrixFactory::BuildCopy(A11);
147 } else {
148 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
149 "MueLu::SchurComplementFactory::Build: Constructing Schur complement for matrix with zero block row or column.");
150 }
151 }
152
153 // Check whether Schur complement operator is a 1x1 block matrix.
154 // If so, unwrap it and return the CrsMatrix based Matrix object
155 // We need this, as single-block smoothers expect it this way.
156 // In case of Thyra GIDs we obtain a Schur complement operator in Thyra GIDs
157 // This may make some special handling in feeding the SchurComplement solver Apply routine
158 // necessary!
159 if (isBlocked) {
160 RCP<BlockedCrsMatrix> bS = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(S);
161
162 if (bS != Teuchos::null && bS->Rows() == 1 && bS->Cols() == 1) {
163 RCP<Matrix> temp = bS->getCrsMatrix();
164 S.swap(temp);
165 }
166 }
167
168 return S;
169}
170
171} // namespace MueLu
172
173#endif /* MUELU_SCHURCOMPLEMENTFACTORY_DEF_HPP_ */
MueLu::DefaultScalar Scalar
Exception indicating invalid cast attempted.
Exception throws to report errors in the internal logical of the program.
void Input(Level &level, const std::string &varName) const
T Get(Level &level, const std::string &varName) const
void Set(Level &level, const std::string &varName, const T &data) const
const RCP< const FactoryBase > GetFactory(const std::string &varName) const
Default implementation of FactoryAcceptor::GetFactory().
Timer to be used in factories. Similar to Monitor but with additional timers.
Class that holds all level-specific information.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput().
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access)....
static const RCP< const NoFactory > getRCP()
Static Get() functions.
virtual const Teuchos::ParameterList & GetParameterList() const
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void DeclareInput(Level &currentLevel) const
Input.
void Build(Level &currentLevel) const
Build an object with this factory.
RCP< Matrix > ComputeSchurComplement(RCP< BlockedCrsMatrix > &bA, RCP< Matrix > &Ainv) const
Schur complement calculation method.
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
Namespace for MueLu classes and methods.
@ Statistics2
Print even more statistics.
@ Statistics1
Print more statistics.